1. 程式人生 > >【最短路徑樹優化】 uva 1416 Warface And Logistics

【最短路徑樹優化】 uva 1416 Warface And Logistics

題目大意:

給出一張無向圖,求刪除一條邊後,對於所有的點對(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;
}