【最短路径树优化】 uva 1416 Warface And Logistics

题目大意:

给出一张无向图,求删除一条边后,对于所有的点对(i,j)使得 c = Sum(d[i][j)]最大的值。

 

分析:

如果仅仅是枚举删除某一条边,是非常差的做法,我们要得到以下几点信息:

首先我们要明确,如果删除这么一条边——不在任何一条最短路径a->b上的边,那么显然c的值不会受到任何的改变。因此我们需要尝试枚举删除的边,都应该在某条最短路上。

 

在求初始c的时候,我们进行n遍djikstra算法。求得以每个节点为起点,到所有其他节点距离和地值。在这个过程中记录每条边地前驱,目的是在算法结束以后,能够找到哪些边是最短路上的边记录他们的编号,并且对于所有的这些边,把当前节点纳入囊中,意味着这条边是哪些节点最短路径上的值,从而让这些特定节点重新调用一边最短路算法计算。

 

#include 
#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;
	vector	G[maxn];
	vector 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 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;
}

 

你可能感兴趣的:(【最短路径】)