版权声明:版权声明:本文为博主原创文章,未经博主允许不得转载,欢迎添加友链。 https://blog.csdn.net/zzk_233/article/details/82915414
原来k≤50。。我还担心开不下。。
设代表当前点在误差小于等于k时到达终点的情况数量
首先求出n到每个点的最短路。然后dfs,每次如果dis[to]-dis[u]+edge[i].val≤k那么就可以更新。如果搜过的点出现过那么直接-1
最后返回dfs的值(也就是f[1][K])即可
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
using namespace std;
typedef long long ll;
int T,n,m,K,p;
struct node
{
int to;
int nxt;
int val;
}edge[400005];
int head[100005];
int f[100005][52];
int used[100005];
int us[100005][52];
int dis[100005];
int cnt=1;
void init()
{
memset(head,-1,sizeof(head));
memset(f,0,sizeof(f));
memset(us,0,sizeof(us));
cnt=1;
}
void add(int from,int to,int val)
{
edge[cnt].to=to;
edge[cnt].val=val;
edge[cnt].nxt=head[from];
head[from]=cnt++;
}
queue<int>M;
void spfa()
{
memset(dis,0x3f,sizeof(dis));
memset(used,0,sizeof(used));
dis[n]=0;
used[n]=1;
M.push(n);
while(!M.empty())
{
int u=M.front();M.pop();
for(int i=head[u];i!=-1;i=edge[i].nxt)
{
if(i%2==1)continue;
int to=edge[i].to;
if(dis[to]>dis[u]+edge[i].val)
{
dis[to]=dis[u]+edge[i].val;
if(used[to])continue;
used[to]=1;M.push(to);
}
}
used[u]=0;
}
}
int dfs(int u,int k)
{
if(us[u][k])return -1;
if(f[u][k])return f[u][k];
us[u][k]=1;f[u][k]=(u==n?1:0);
for(int i=head[u];i!=-1;i=edge[i].nxt)
{
if(i%2==0)continue;
int to=edge[i].to,w,op;
if((w=(k-(dis[to]+edge[i].val-dis[u])))>=0)
{
if((op=dfs(to,w))==-1)return /*f[u][k]*/=-1;
else f[u][k]+=op,f[u][k]%=p;
}
}
return us[u][k]=0,f[u][k];
}
int main()
{
scanf("%d",&T);
while(T--)
{
init();
scanf("%d%d%d%d",&n,&m,&K,&p);
for(int i=1;i<=m;i++)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
add(a,b,c);
add(b,a,c);
}
spfa();printf("%d\n",dfs(1,K));
}
return 0;
}