题意:
策策同学特别喜欢逛公园。 公园可以看成一张 N 个点 M 条边构成的有向图,且没有自环和重边。其中 1 号点是公园的入口, N 号点是公园的出口,每条边有一个非负权值,代表策策经过这条边所要花的时间。
策策每天都会去逛公园,他总是从 1 号点进去,从 N 号点出来。
策策喜欢新鲜的事物,他不希望有两天逛公园的路线完全一样,同时策策还是一个特别热爱学习的好孩子,他不希望每天在逛公园这件事上花费太多的时间。如果 1 号点到 N 号点的最短路长为 d,那么策策只会喜欢长度不超过 d+K 的路线。
策策同学想知道总共有多少条满足条件的路线,你能帮帮他吗?
为避免输出过大,答案对 P 取模。
如果有无穷多条合法的路线,请输出 −1 。
n<=1e5,m<=2e5,K<=50,1≤P≤1e9,0≤ci≤1000。
思路:因为K很小,建立以1为源点的最短路图,在最短路图上进行DP计数
dp[i][j]表示当前在点i,比最短路线多走j时间的方案数
在1到N的最短路上可能有环,这样会出现-1的情况,同时还有边长为0的存在,这两个问题都可以使用拓扑排序解决
对于-1拓扑排序后直接判断
对于边长为0按照拓扑序进行转移
1 #include<cstdio> 2 #include<cstring> 3 #include<string> 4 #include<cmath> 5 #include<iostream> 6 #include<algorithm> 7 #include<map> 8 #include<set> 9 #include<queue> 10 #include<vector> 11 using namespace std; 12 typedef long long ll; 13 typedef unsigned int uint; 14 typedef unsigned long long ull; 15 typedef pair<int,int> PII; 16 typedef vector<int> VI; 17 #define fi first 18 #define se second 19 #define MP make_pair 20 #define N 110000 21 #define M 210000 22 #define eps 1e-8 23 #define pi acos(-1) 24 priority_queue<pair<int,int> > q; 25 26 int dp[N][51],head[M],vet[M],nxt[M],len[M],head2[M],vet2[M],nxt2[M],len2[M], 27 dis[N],dis2[N],vis[N],p[N],d[N],tot,tot2; 28 29 void add(int a,int b,int c) 30 { 31 nxt[++tot]=head[a]; 32 vet[tot]=b; 33 len[tot]=c; 34 head[a]=tot; 35 } 36 37 void add2(int a,int b,int c) 38 { 39 nxt2[++tot2]=head2[a]; 40 vet2[tot2]=b; 41 len2[tot2]=c; 42 head2[a]=tot2; 43 } 44 45 int main() 46 { 47 //freopen("uoj331.in","r",stdin); 48 // freopen("uoj331.out","w",stdout); 49 int cas; 50 scanf("%d",&cas); 51 for(int v1=1;v1<=cas;v1++) 52 { 53 int n,m,K,MOD; 54 scanf("%d%d%d%d",&n,&m,&K,&MOD); 55 tot=tot2=0; 56 memset(head,0,sizeof(head)); 57 memset(head2,0,sizeof(head2)); 58 for(int i=1;i<=m;i++) 59 { 60 int x,y,z; 61 scanf("%d%d%d",&x,&y,&z); 62 add(x,y,z); 63 add2(y,x,z); 64 } 65 //printf("readend "); 66 memset(vis,0,sizeof(vis)); 67 memset(dis,0x3f,sizeof(dis)); 68 memset(d,0,sizeof(d)); 69 q.push(MP(0,1)); dis[1]=0; 70 while(!q.empty()) 71 { 72 int u=q.top().se; 73 q.pop(); 74 if(vis[u]) continue; 75 vis[u]=1; 76 int e=head[u]; 77 while(e) 78 { 79 int v=vet[e]; 80 if(dis[u]+len[e]<dis[v]) 81 { 82 dis[v]=dis[u]+len[e]; 83 q.push(MP(-dis[v],v)); 84 } 85 e=nxt[e]; 86 } 87 } 88 //printf("dijk1end "); 89 memset(vis,0,sizeof(vis)); 90 memset(dis2,0x3f,sizeof(dis2)); 91 q.push(MP(0,n)); dis2[n]=0; 92 while(!q.empty()) 93 { 94 int u=q.top().se; 95 q.pop(); 96 if(vis[u]) continue; 97 vis[u]=1; 98 int e=head2[u]; 99 while(e) 100 { 101 int v=vet2[e]; 102 if(dis2[u]+len2[e]<dis2[v]) 103 { 104 dis2[v]=dis2[u]+len2[e]; 105 q.push(MP(-dis2[v],v)); 106 } 107 e=nxt2[e]; 108 } 109 } 110 //printf("dijk2end "); 111 for(int i=1;i<=n;i++) 112 { 113 int e=head[i]; 114 while(e) 115 { 116 int v=vet[e]; 117 if(dis[i]+len[e]==dis[v]) d[v]++; 118 e=nxt[e]; 119 } 120 } 121 tot=0; 122 for(int i=1;i<=n;i++) 123 if(!d[i]) p[++tot]=i; 124 //printf("%d ",tot); 125 for(int i=1;i<=tot;i++) 126 { 127 int u=p[i]; 128 int e=head[u]; 129 while(e) 130 { 131 int v=vet[e]; 132 if(dis[u]+len[e]==dis[v]) 133 { 134 d[v]--; 135 if(!d[v]) p[++tot]=v; 136 } 137 e=nxt[e]; 138 } 139 } 140 //printf("topoend "); 141 int flag=1; 142 for(int i=1;i<=n;i++) 143 if(d[i]&&dis[i]+dis2[i]<=dis[n]+K) 144 { 145 printf("-1 "); 146 flag=0; 147 break; 148 } 149 if(!flag) continue; 150 memset(dp,0,sizeof(dp)); 151 dp[1][0]=1; 152 for(int k=0;k<=K;k++) 153 { 154 for(int i=1;i<=tot;i++) 155 { 156 int u=p[i]; 157 int e=head[u]; 158 while(e) 159 { 160 int v=vet[e]; 161 if(dis[u]+len[e]==dis[v]) dp[v][k]=(dp[v][k]+dp[u][k])%MOD; 162 e=nxt[e]; 163 } 164 } 165 166 for(int i=1;i<=n;i++) 167 { 168 int e=head[i]; 169 while(e) 170 { 171 int v=vet[e]; 172 int t=k+dis[i]+len[e]-dis[v]; 173 if(dis[i]+len[e]!=dis[v]&&t<=K) dp[v][t]=(dp[v][t]+dp[i][k])%MOD; 174 e=nxt[e]; 175 } 176 } 177 } 178 ll ans=0; 179 for(int i=0;i<=K;i++) ans=(ans+dp[n][i])%MOD; 180 printf("%lld ",ans); 181 } 182 return 0; 183 }