【最短路徑樹優化】 uva 1416 Warface And Logistics
阿新 • • 發佈:2018-12-12
題目大意:
給出一張無向圖,求刪除一條邊後,對於所有的點對(i,j)使得 c = Sum(d[i][j)]最大的值。
分析:
如果僅僅是列舉刪除某一條邊,是非常差的做法,我們要得到以下幾點資訊:
首先我們要明確,如果刪除這麼一條邊——不在任何一條最短路徑a->b上的邊,那麼顯然c的值不會受到任何的改變。因此我們需要嘗試列舉刪除的邊,都應該在某條最短路上。
在求初始c的時候,我們進行n遍djikstra演算法。求得以每個節點為起點,到所有其他節點距離和地值。在這個過程中記錄每條邊地前驅,目的是在演算法結束以後,能夠找到哪些邊是最短路上的邊記錄他們的編號,並且對於所有的這些邊,把當前節點納入囊中,意味著這條邊是哪些節點最短路徑上的值,從而讓這些特定節點重新呼叫一邊最短路演算法計算。
#include <bits/stdc++.h> #define CLR(arr) memset(arr,0,sizeof(arr)) #define FUL(arr) memset(arr,0x3f,sizeof(arr)) #define NEG(arr) memset(arr,-1,sizeof(arr)) const int inf = 0x3f3f3f3f; using namespace std; const int maxn = 120; const int maxm = 1100; typedef long long ll; int n,m,L; struct HeapNode{ int u,d; bool operator < (const HeapNode& rhs) const { return d > rhs.d; } }; struct Edge{ int u,v,dist; bool flag; }; struct Dijkstra{ int d[maxn]; int p[maxn]; bool done[maxn]; int ecnt; int n; vector<Edge> edge; vector<int> G[maxn]; vector<int> tree[maxm*3]; void AddEdge(int u,int v,int d){ edge.push_back(Edge{u,v,d,1}); G[u].push_back(ecnt++); edge.push_back(Edge{v,u,d,1}); G[v].push_back(ecnt++); } void init(int _n){ n = _n; for (int i = 0 ; i < n ;++i){ G[i].clear(); tree[i].clear(); } edge.clear(); ecnt = 0; } ll dijkstra(int s){ FUL(d); CLR(done); NEG(p); priority_queue<HeapNode> Q; d[s] = 0; Q.push(HeapNode{s,0}); while(!Q.empty()) { HeapNode x = Q.top(); Q.pop(); int u = x.u; if(done[u]) continue; done[u] = true; for (int i = 0 ; i < G[u].size() ;++i) { Edge &e = edge[G[u][i]]; if(!e.flag) continue; if(d[e.v] > d[u] + e.dist) { d[e.v] = d[u] + e.dist; Q.push(HeapNode{e.v,d[e.v]}); p[e.v] = G[u][i]; } } } ll ans = 0; for (int i = 0 ; i < n ; ++i) if(i != s) ans += ( d[i] == inf ? L : d[i]); return ans; } void deleteEdge(int idx){ edge[idx].flag = 0; edge[idx^1].flag = 0; } void restoreEdge(int idx){ edge[idx].flag = 1; edge[idx^1].flag = 1; } void GetTree(int s){ for (int i = 0 ; i < n ; ++i) { if(i == s || p[i] == -1) continue; tree[p[i]].push_back(s); } } }; ll D[maxn]; int main() { while(scanf("%d%d%d",&n,&m,&L)==3) { int a,b,c; Dijkstra solver; solver.init(n); for (int i = 0 ; i < m ; ++i) { cin >> a >> b >> c; if(a==b) continue; a--;b--; solver.AddEdge(a,b,c); } ll ans1 = 0 , ans2 = 0; for (int i = 0 ; i < n ; ++i) { D[i] = solver.dijkstra(i); ans1 += D[i]; solver.GetTree(i); } ll tmp = 0; for (int i = 0 ; i < solver.edge.size() ; i++){ solver.deleteEdge(i); if (i % 2 == 0) tmp = ans1; for (int j = 0 ; j < solver.tree[i].size() ; ++j) { int k = solver.tree[i][j]; tmp -= D[k]; tmp += solver.dijkstra(k); } ans2 = max(ans2,tmp); solver.restoreEdge(i); } cout << ans1 <<' ' << ans2 << endl; } return 0; }