题目分析:
首先考虑无数条的情况。出现这种情况一定是一条合法路径经过了$ 0 $环中的点。那么预先判出$ 0 $环中的点和其与$ 1 $和$ n $的距离。加起来若离最短路径不超过$ k $则输出$ -1 $,否则这些点必定不被经过,接着dp后效性消失。由于每条边转移了$ k $次它的起点到终点的状态,所以总时间复杂度为$ O(n+mk) $,可以通过所有数据。
代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstdlib> 4 #include<cstring> 5 #include<queue> 6 #include<vector> 7 #include<stack> 8 using namespace std; 9 10 typedef pair<int,int> pr; 11 12 const int maxn = 105000; 13 14 int n,m,k,p; 15 vector<pair<int,int> > g[maxn],rg[maxn]; 16 vector <int> ng[maxn]; 17 18 int dfn[maxn],low[maxn],instack[maxn],scc[maxn],cl; 19 int f[maxn][52],arr[maxn][52]; 20 stack <int> sta; 21 22 void init(){ 23 memset(dfn,0,sizeof(dfn)); 24 memset(arr,0,sizeof(arr)); 25 memset(low,0,sizeof(low)); 26 memset(instack,0,sizeof(instack)); 27 memset(scc,0,sizeof(scc)); 28 memset(f,0,sizeof(f)); 29 cl = 0; 30 } 31 32 void tarjan(int now){ 33 low[now] = dfn[now] = ++cl; 34 sta.push(now); 35 for(int i=0;i<ng[now].size();i++){ 36 int k = ng[now][i]; if(instack[k]) continue; 37 if(dfn[k]) { low[now] = min(low[now],dfn[k]); } 38 else{ tarjan(k); low[now] = min(low[now],low[k]); } 39 } 40 if(low[now] == dfn[now]){ 41 stack<int> tpp;int num = 0; 42 while(true){ 43 int tp = sta.top();sta.pop();tpp.push(tp);num++; 44 instack[tp] = 1; scc[tp]=1; 45 if(now == tp) break; 46 } 47 if(num == 1) scc[tpp.top()] = 0; 48 } 49 } 50 51 void read(){ 52 scanf("%d%d%d%d",&n,&m,&k,&p); 53 for(int i=1;i<=n;i++) g[i].clear(); 54 for(int j=1;j<=n;j++) ng[j].clear(); 55 for(int j=1;j<=n;j++) rg[j].clear(); 56 for(int i=1;i<=m;i++){ 57 int u,v,w; scanf("%d%d%d",&u,&v,&w); 58 g[u].push_back(make_pair(v,w)); 59 rg[v].push_back(make_pair(u,w)); 60 if(w == 0) ng[u].push_back(v); 61 } 62 } 63 64 int res; 65 int d[maxn][2]; 66 priority_queue<pr,vector<pr>,greater<pr> > pq; 67 void solve_dist(){ 68 memset(d,0x3f,sizeof(d)); 69 pq.push(make_pair(0,1)); 70 while(!pq.empty()){ 71 pair<int,int> tp = pq.top();pq.pop(); 72 if(d[tp.second][0] > 1e9) d[tp.second][0] = tp.first; 73 else continue; 74 for(int j=0;j<g[tp.second].size();j++){ 75 int nxt = g[tp.second][j].first,data = g[tp.second][j].second; 76 data += d[tp.second][0]; 77 if(data > d[nxt][0]) continue; 78 pq.push(make_pair(data,nxt)); 79 } 80 } 81 res = d[n][0]; 82 pq.push(make_pair(0,n)); 83 while(!pq.empty()){ 84 pair<int,int> tp = pq.top();pq.pop(); 85 if(d[tp.second][1] > 1e9) d[tp.second][1] = tp.first; 86 else continue; 87 for(int j=0;j<rg[tp.second].size();j++){ 88 int nxt = rg[tp.second][j].first,data = rg[tp.second][j].second; 89 data += d[tp.second][1]; 90 if(data > d[nxt][1]) continue; 91 pq.push(make_pair(data,nxt)); 92 } 93 } 94 } 95 96 void dfs(int now,int lw){ 97 if(arr[now][lw]) return; 98 int nowd = d[now][0]+lw;arr[now][lw] = 1; 99 for(int j=0;j<rg[now].size();j++){ 100 int nxt = rg[now][j].first,data = rg[now][j].second; 101 if(scc[nxt])continue; 102 int nd = nowd-data; nd -= d[nxt][0]; 103 if(nd < 0) continue; 104 if(nd > k) continue; 105 dfs(nxt,nd); 106 f[now][lw] += f[nxt][nd]; f[now][lw] %= p; 107 } 108 } 109 110 void work(){ 111 for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i); 112 if(scc[1]||scc[n]) {puts("-1");return;} 113 114 solve_dist(); 115 116 for(int i=1;i<=n;i++) 117 if(scc[i]) if(d[i][0]+d[i][1]<=res+k){puts("-1");return;} 118 119 f[1][0] = 1;arr[1][0] = 1;int ans = 0; 120 for(int i=0;i<=k;i++) { 121 dfs(n,i);ans += f[n][i]; ans %= p; 122 } 123 printf("%d\n",ans); 124 } 125 126 int main(){ 127 int t; scanf("%d",&t); 128 while(t--){ init(); read(); work(); } 129 return 0; 130 }
原文:https://www.cnblogs.com/Menhera/p/9086027.html