1. 程式人生 > >[NOIP2017] 逛公園 【最短路】【強連通分量】

[NOIP2017] 逛公園 【最短路】【強連通分量】

size def con tar 出現 typedef esp pair string

題目分析:

首先考慮無數條的情況。出現這種情況一定是一條合法路徑經過了$ 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 }

[NOIP2017] 逛公園 【最短路】【強連通分量】