注意数据中 k <= 50,考虑从这里入手解决问题
设 f [ i ] [ j ] 表示 已经到 i 点,最多还能比最短路程多走 j 的长度而不超过限制时的方案数
处理出终点到每个点的最短路程 dis [ i ]
那么对于一条边 (a,b,c), f [ a ] [ j ] --> f [ b ] [ j - (dis[a]-dis[b]+c) ]
那么对于每一个状态
如果直接DP顺序不好确定,所以考虑用记忆化搜索实现
然后考虑判断无穷多的路线
显然如果 dfs 时重复走到同一个状态说明出现了无穷多路线,所以开一个数组存一下当前走过的状态就好了
求最短路用的是Dijkstra
多组数据一定要记得清空
#include<cstdio> #include<algorithm> #include<cmath> #include<cstring> #include<iostream> #include<queue> #include<vector> using namespace std; typedef long long ll; inline int read() { int x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } return x*f; } const int N=1e5+7,INF=0x3f3f3f3f; int T,n,m,K,mo; inline int fk(int x) { return x>=mo ? x-mo : x; } int fir[N],from[N<<2],to[N<<2],val[N<<2],cntt;//存正图 inline void add(int &a,int &b,int &c) { from[++cntt]=fir[a]; fir[a]=cntt; to[cntt]=b; val[cntt]=c; } vector <int> v[N],g[N];//存反图 int dis[N]; struct data { int pos,dis; inline bool operator < (const data &tmp) const { return dis>tmp.dis; } }; priority_queue <data> q; void Dijk()//Dijkstra不解释 { memset(dis,INF,sizeof(dis)); dis[n]=0; q.push((data){n,0}); data x; int len; while(!q.empty()) { x=q.top(); q.pop(); if(dis[x.pos]!=x.dis) continue; len=v[x.pos].size(); for(int i=0;i<len;i++) { int u=v[x.pos][i],w=g[x.pos][i]; if(dis[u]>x.dis+w) dis[u]=x.dis+w,q.push((data){u,dis[u]}); } } } int f[N][57]; bool vis[N][57],flag; void dfs(int x,int k) { if(flag) return; vis[x][k]=1; if(x==n) f[x][k]=1;//f[n][k]初始为1 //注意不能初始把所有f[n][k]=1,因为是记忆化,如果初始有值就不会dfs下去,而f[n][k]最终可能有不止一种方案 for(int i=fir[x];i;i=from[i]) { int &v=to[i],w=k-(dis[v]-dis[x]+val[i]); if(w<0) continue;//判一下w是否符合限制 if(vis[v][w])/*判断是否有无穷多的解*/ { flag=1; vis[x][k]=0; return; }//退出前记得vis=0 if(!f[v][w]) dfs(v,w); f[x][k]=fk(f[x][k]+f[v][w]);//记忆化 } vis[x][k]=0; } inline void clr()//初始化 { memset(f,0,sizeof(f)); memset(fir,0,sizeof(fir)); for(int i=1;i<=n;i++) v[i].clear(),g[i].clear(); cntt=flag=0; } int main() { int a,b,c; T=read(); while(T--) { n=read(); m=read(); K=read(); mo=read(); clr(); for(int i=1;i<=m;i++) { a=read(),b=read(),c=read(); add(a,b,c); v[b].push_back(a); g[b].push_back(c); } Dijk(); dfs(1,K); printf("%d\n",flag ? -1 : f[1][K]);//最终答案是f[1][K] } return 0; }