problem
Description
策策同学特别喜欢逛公园。公园可以看成一张��个点��条边构成的有向图,且没有自环和重边。其中1号点是公园的入口,��号点是公园的出口,每条边有一个非负权值,代表策策经过这条边所要花的时间。
策策每天都会去逛公园,他总是从1号点进去,从��号点出来。
策策喜欢新鲜的事物,他不希望有两天逛公园的路线完全一样,同时策策还是一个特别热爱学习的好孩子,他不希望每天在逛公园这件事上花费太多的时间。如果1号点到��号点的最短路长为��,那么策策只会喜欢长度不超过�� + ��的路线。
策策同学想知道总共有多少条满足条件的路线,你能帮帮他吗?
为避免输出过大,答案对��取模。
如果有无穷多条合法的路线,请输出−1。
Input
输入文件名为 park.in 。
第一行包含一个整数 ��, 代表数据组数。
接下来��组数据,对于每组数据:
第一行包含四个整数 ��,��,��,��,每两个整数之间用一个空格隔开。
接下来��行,每行三个整数�� �� ,�� �� ,�� �� , 代表编号为�� �� ,�� �� 的点之间有一条权值为 �� �� 的有向边,每两个整数之间用一个空格隔开。
Output
输出文件包含 ��行,每行一个整数代表答案。
Sample Input
2
5 7 2 10
1 2 1
2 4 0
4 5 2
2 3 2
3 4 1
3 5 2
1 5 3
2 2 0 10
1 2 0
2 1 0
Sample Output
3
-1
样例说明:
对于第一组数据,最短路为 3。
1 – 5, 1 – 2 – 4 – 5, 1 – 2 – 3 – 5 为 3 条合法路径。
Data Constraint
对于不同的测试点,我们约定各种参数的规模 不会超过如下
对于 100%的数据, 1 ≤ �� ≤ 10^ 9 ,1 ≤ �� �� ,�� �� ≤ �� ,0 ≤ �� �� ≤ 1000。
analysis
有人说这是防AK题?不算吧……(只不过我并没有做出来顶乱用)
首先用邻接表存边跑一遍spfa,
dis[i]
表示1到i的最短路长度(不要和我说你不会spfa)
设
f[i][j]
表示从1到i的所有路径里,比
dis[n]
大K的路径条数
所以有
看到这个,你以为是 DP?
记忆化搜索!
我们从 n 开始倒着搜索,若
那么我们最大的敌人——判0环呢?
若
f[x][y]
这个状态在一遍dfs里出现两次,那就是有0环,return就好,开个数组标记一下
finally
code
#include<stdio.h>
#include<cstring>
#define MAXN 100001
#define MAXM 200001
using namespace std;
int last[MAXM],next[MAXM],tov[MAXM],len[MAXM];
int Last[MAXM],Next[MAXM],Tov[MAXM],Len[MAXM];
int dis[MAXN],queue[10*MAXN];
int f[MAXN][51],c[MAXN][51];
int n,m,k,p,t,tot,ans;
bool bo,bz[MAXN];
void insert(int x,int y,int z)
{
next[++tot]=last[x];
last[x]=tot;
tov[tot]=y;
len[tot]=z;
Next[tot]=Last[y];
Last[y]=tot;
Tov[tot]=x;
Len[tot]=z;
}
int dfs(int x,int k)
{
if(~f[x][k])return f[x][k];
c[x][k]=1;
f[x][k]=0;
for(int i=Last[x];i;i=Next[i])
{
int j=Tov[i],t=dis[x]-dis[j]+k-Len[i];
if(t<0)continue;
if(c[j][t])bo=0;
(f[x][k]+=dfs(j,t))%=p;
}
c[x][k]=0;
return f[x][k];
}
int main()
{
freopen("park.in","r",stdin);
freopen("park.out","w",stdout);
scanf("%d",&t);
while (t--)
{
scanf("%d%d%d%d",&n,&m,&k,&p);
tot=0;
memset(last,0,sizeof(last));
memset(next,0,sizeof(next));
memset(tov,0,sizeof(tov));
memset(len,0,sizeof(len));
memset(Last,0,sizeof(last));
memset(Next,0,sizeof(next));
memset(Tov,0,sizeof(tov));
memset(Len,0,sizeof(len));
memset(c,0,sizeof(c));
memset(bz,1,sizeof(bz));
memset(f,-1,sizeof(f));
memset(dis,63,sizeof(dis));
for (int i=1;i<=m;i++)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
insert(x,y,z);
}
int head=0,tail=1;
bz[1]=dis[1]=ans=0;
queue[1]=1;
while (head!=tail)
{
head=(head+1==10*MAXN?0:head+1);
int now=queue[head];
for (int i=last[now];i;i=next[i])
{
int j=tov[i];
if (dis[now]+len[i]<dis[j])
{
dis[j]=dis[now]+len[i];
if (bz[j])
{
bz[j]=0;
tail=(tail+1==10*MAXN?0:tail+1);
queue[tail]=j;
}
}
}
bz[now]=1;
}
bo=1;
f[1][0]=1;
for (int i=0;i<=k;i++)(ans+=dfs(n,i))%=p;
dfs(n,k+1);
if (!bo)
{
printf("-1\n");
}
else printf("%d\n",ans);
}
return 0;
}