P3953 逛公园
首先可以想到,走到一个点时,只要长度是一定的,那么后面怎么走跟前面无关。这就是他和普通的最短路不同的原因。故可以考虑记忆化搜索
先求出最短路
怎么搜索呢?用
这一波分析里可以看出还要先反向建图跑一遍预处理出每个点到
AC代码
#include<bits/stdc++.h>
const int maxk=60;
const int maxn=100010;
const int maxm=200010;
using namespace std;
int T,n,m,k,p;
int tot,to[maxm],nxt[maxm],len[maxm],head[maxn];
int Rtot,Rto[maxm],Rnxt[maxm],Rlen[maxm],Rhead[maxn];
int dis[maxn],f[maxn][maxk];
bool vis[maxn],in[maxn][maxk];
priority_queue< pair<int,int> > Q;
inline void Add(int u,int v,int w) {to[++tot]=v,nxt[tot]=head[u],len[tot]=w,head[u]=tot;}
inline void RAdd(int u,int v,int w) {Rto[++Rtot]=v,Rnxt[Rtot]=Rhead[u],Rlen[Rtot]=w,Rhead[u]=Rtot;}
void init()
{
tot=Rtot=0;
memset(head,0,sizeof(head));
memset(Rhead,0,sizeof(Rhead));
memset(dis,0x3f,sizeof(dis));
memset(vis,0,sizeof(vis));
memset(f,0,sizeof(f));
memset(in,0,sizeof(in));
}
void RDijkstra()
{
dis[n]=0;
Q.push(make_pair(0,n));
while(!Q.empty())
{
int u=Q.top().second;Q.pop();
if(vis[u]) continue;
vis[u]=true;
for(int i=Rhead[u];i;i=Rnxt[i])
{
int v=Rto[i];
if(dis[v]>dis[u]+Rlen[i])
{
dis[v]=dis[u]+Rlen[i];
Q.push(make_pair(-dis[v],v));
}
}
}
}
int dfs(int u,int K)
{
if(in[u][K]) return -1;
if(f[u][K]) return f[u][K];
in[u][K]=1;
if(u==n) f[u][K]=1;
for(int i=head[u];i;i=nxt[i])
{
int v=to[i];
int dt=dis[v]+len[i]-dis[u];
if(dt<=K)
{
int w=dfs(v,K-dt);
if(w==-1) return -1;
f[u][K]=(f[u][K]+w)%p;
}
}
in[u][K]=0;
return f[u][K];
}
int main()
{
scanf("%d",&T);
for(int t=1;t<=T;t++)
{
init();
scanf("%d%d%d%d",&n,&m,&k,&p);
for(int i=1,u,v,w;i<=m;i++)
{
scanf("%d%d%d",&u,&v,&w);
Add(u,v,w);RAdd(v,u,w);
}
RDijkstra();
printf("%d\n",dfs(1,k));
}
return 0;
}