題意:c++
給出一個圖,n <= 10^5,給出起點s和終點t數組
有向邊,每花費一個單位的錢能夠選擇一條邊,把它的邊權-1,可是邊權必須>0,spa
好比邊權爲w,最多花費w-1,邊權變爲1,可是不能把邊權變爲0debug
如今要選擇一條最短路從s到tcode
題目保證s到t至少有一條路blog
問這個圖it
1.哪些邊是必定會通過的io
2.哪些邊是能夠改變邊權使得它必定會通過的,最少花費多少?class
3.哪些邊是不管怎麼改變邊權,都不知足必定會通過的bug
先跑一遍dijkstra,求出ds數組,ds[i]表示s到i的最短距離
再把邊的方向反過來,求出dt數組,dt[i]表示t到i的最短距離
對於1
一條邊必定會通過,說明每一條最短路都通過它,那麼咱們把全部的最短路的邊拿出來,建一個新圖,新圖的橋就是必定會通過的邊
那怎麼判斷邊e=(u,v,w)是否屬於某一條最短路呢?
若是e屬於某一條最短路,必定有:
ds[u] + w + dt[v] = ds[t]
問題1解決
對於2
一條邊e=(u,v,w)修改後,必定會通過它,假設修改邊權花費了x:
則有:ds[u] + w - x + dt[v] = ds[t] - 1
而且:w - x > 0
即:x = ds[u] + w + dt[v] - ds[t] + 1
且:x < w
對於3
除了1的邊和2的邊,其他的邊都屬於3
這道題,原本不難,可是沒有考慮2個點,debug 了很久
1.圖沒有自環,可是有多重邊,在求圖的橋的時候沒有處理多重邊,wa 12
2.新建的最短路圖,在求橋的時候,我是調用了tagjan(1),表示從節點1開始處理,
可是對於這個新圖,1可能沒有和s,t在同一個聯通塊(題目保證s到t有路徑,則s和t必定在一個聯通塊),wa 59
應該是調用tarjan(s)或者targan(t)
代碼:
//File Name: cf567E.cpp //Created Time: 2017年08月30日 星期三 18時45分21秒 #include <bits/stdc++.h> #define LL long long #define pii pair<int,int> #define pli pair<LL,int> #define fir first #define sec second using namespace std; const int MAXN = 100000 + 5; const LL INF = 100000000000000; struct Edge{ int from,to,cost; }; Edge edge[MAXN]; LL ds[MAXN],dt[MAXN];//ds[i],dt[i]分別表示i到s,t的最短距離 vector<int> G[MAXN]; //G[u]保存edge中from=u的邊的id,即在edge中的位置 bool bridge[MAXN]; //第i條邊在最短路圖中是bridge,則bridge[i] = true void clear_G(const int n){ for(int i(1);i<=n;++i) G[i].clear(); } priority_queue<pli> que; bool vis[MAXN]; void dijkstra(const int n,const int m,const int s,LL *ds,const bool rev){ for(int i(1);i<=n;++i) ds[i] = INF; ds[s] = 0; memset(vis,false,sizeof vis); while(!que.empty()) que.pop(); que.push(pli(0,s)); while(!que.empty()){ pli tmp = que.top(); que.pop(); int u(tmp.sec); LL dis(-tmp.fir); if(vis[u] || dis != ds[u]) continue; vis[u] = true; for(auto cur:G[u]){ int v; if(rev) v = edge[cur].from; else v = edge[cur].to; int w(edge[cur].cost); if(!vis[v] && ds[v] > ds[u] + w){ ds[v] = ds[u] + w; que.push(pli(-ds[v],v)); } } } } int dfs_clock; int pre[MAXN]; int low[MAXN]; void dfs(const int u,const int fa){ low[u] = pre[u] = ++dfs_clock; bool flag = false; for(auto cur:G[u]){ int v = edge[cur].to; if(v == u) v = edge[cur].from; if(v == fa && !flag){ flag = true; continue; } if(!pre[v]){ dfs(v,u); low[u] = min(low[v],low[u]); if(low[v] > pre[u]) bridge[cur] = true; } else if(pre[v] < low[u]) low[u] = pre[v]; } } void find_bridge(const int n,const int s){ dfs_clock = 0; memset(pre,0,sizeof pre); memset(low,0,sizeof low); memset(bridge,false,sizeof bridge); dfs(s,0); } void solve(const int n,const int m,const int s,const int t){ clear_G(n); for(int i(1);i<=m;++i) G[edge[i].from].push_back(i); dijkstra(n,m,s,ds,false); clear_G(n); for(int i(1);i<=m;++i) G[edge[i].to].push_back(i); dijkstra(n,m,t,dt,true); clear_G(n); for(int i(1);i<=m;++i){ int u(edge[i].from),v(edge[i].to),w(edge[i].cost); if(ds[u] + dt[v] + w == ds[t]){ G[u].push_back(i); G[v].push_back(i); } } find_bridge(n,s); for(int i(1);i<=m;++i){ int u(edge[i].from),v(edge[i].to),w(edge[i].cost); if(ds[u] + dt[v] + w == ds[t]){ if(bridge[i]) puts("YES"); else if(w > 1) puts("CAN 1"); else puts("NO"); } else{ LL cur = ds[u] + dt[v] + w - ds[t] + 1; if(w - cur > 0) printf("CAN %lld\n",cur); else puts("NO"); } } } int main(){ int n,m,s,t; scanf("%d %d %d %d",&n,&m,&s,&t); for(int i(1),u,v,w;i<=m;++i){ scanf("%d %d %d",&u,&v,&w); edge[i].from = u; edge[i].to = v; edge[i].cost = w; } solve(n,m,s,t); return 0; }