UVALive 4080 Warfare And Logistics(Dijkstra+最短路树)



题意:给定一个n节点m条边的无向图,定义c为每对顶点的最短路之和,要求删掉一条边重新求一个c值c‘,求出c‘最大值.

思路:如果用floyd算法计算c,每尝试删除一条边都要重新计算一次,时间复杂度为O(n*n*n*m),很难承受。如果用n次Dijkstra计算单源最短路,时间复杂度味O(n*m*m*logn)。虽然看上去比之前的好,但由于佛洛依德算法的常数很小,实际运行时间差不多。这时候,可以考虑最短路树。因为在源点确定的情况下,只要最短路树不被破坏,起点到所有点的距离都不会发生改变。也就是说,只有删除最短路树上的n-1条边,最短路树才需要重新计算。这样,对于每个源点,最多只需求n次最短路而不是m次,时间复杂度降为O(n*n*m*logn),可以承受。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<vector>
#include<map>
#include<queue>
#include<stack>
#include<string>
#include<map>
#include<set>
#define eps 1e-6
#define LL long long
using namespace std;  

const int maxn = 155 + 5;
const int INF = 1000000000;

int n, m, L;
//Dijkstra
struct Edge {
	int from, to, dist;
	Edge(int u = 0, int v = 0, int d = 0) : from(u), to(v), dist(d) {
	}
};
struct HeapNode {         ///用到的优先队列的结点
	int d, u;
	bool operator < (const HeapNode& rhs) const {
		return d > rhs.d;
	}
};
struct Dijkstra {
	int n, m;  //点数和边数
	vector<Edge> edges;  //边列表
	vector<int> G[maxn];   		//每个节点出发的边编号
	bool done[maxn];            //是否已经永久编号
	int d[maxn];                //s到各个点的距离
	int p[maxn];                //最短路中的上一条边
	int del;

	void init(int n) {
		this->n = n;
		for(int i = 0; i < n; i++) G[i].clear();
		edges.clear();
		del = -1;
	}

	void AddEdge(int from, int to, int dist) {   //如果是无向图需要调用两次
		edges.push_back(Edge(from, to, dist));
		m = edges.size();
		G[from].push_back(m-1);
	}  

	LL dijkstra(int s) {            //求s到所有点的距离
		priority_queue<HeapNode> Q;
		for(int i = 0; i < n; i++) d[i] = INF;
		d[s] = 0;
		memset(done, 0, sizeof(done));
		memset(p, -1, sizeof(p));
		Q.push((HeapNode){0, s});
		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++) if(G[u][i]!=del && G[u][i]!=(del^1)){
				Edge& e = edges[G[u][i]];
				if(d[e.to] > d[u] + e.dist) {
					d[e.to] = d[u] + e.dist;
					p[e.to] = G[u][i];
					Q.push((HeapNode){d[e.to], e.to});
				}
			}
		}
		LL ans = 0;
		for(int u = 0; u < n; u++) if(u != s) {
			if(d[u] == INF) ans += L;
			else ans += d[u];
		}
		return ans;
	}
} solver;

LL ans[2055]; int parent[maxn];
void init() {
	solver.init(n);
	memset(ans, 0, sizeof(ans));
	int u, v, d;
	for(int i = m-1; i >= 0; i--) {
		scanf("%d%d%d", &u, &v, &d);
		u--; v--;
		solver.AddEdge(u, v, d);
		solver.AddEdge(v, u, d);
	}
}

void solve() {
	LL preans = 0;
	for(int s = 0; s < n; s++) {
		int len = solver.dijkstra(s);
		for(int i = 0; i < n; i++) parent[i] = solver.p[i];
		preans += len;
		for(int i = 0; i < 2*m; i++) ans[i] += len;
		for(int son = 0; son < n; son++) if(son != s){
			if(parent[son] == -1) continue;
			solver.del = parent[son];
			ans[parent[son]] = ans[parent[son]^1] = ans[parent[son]] + solver.dijkstra(s) - len;
		}
		solver.del = -1;
	}
	LL del_ans = 0;
	for(int i = 0; i < 2*m; i++) del_ans = max(del_ans, ans[i]);
	cout << preans << " " << del_ans << endl;
	//for(int i = 0; i < 2*m; i++) cout << ans[i] << endl;
}

int main() {
	//freopen("input.txt", "r", stdin);
	while(scanf("%d%d%d", &n, &m, &L) == 3) {
		init();
		solve();
	}
	return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-08-26 11:50:08

UVALive 4080 Warfare And Logistics(Dijkstra+最短路树)的相关文章

UVALive - 4080 Warfare And Logistics (SPFA+最短路树)

题目大意:有N个点,M条路,如果两条路不连通的话,就将这两条路的距离设置为L 现在要求你求出每两点之间的最短距离和 接着要求 求出炸断 给出的M条路中的一条路后,每两点之间的最短距离和的最大值 解题思路:这题跟HDU-2433类似,不过这题的权值是不一样的 但具体的思路是差不多的 先预处理出以每个点为源点的最短路树,并纪录每个点的pre和以每个点为源点的最短距离和,这样就可以求出每两点之间的最短距离和了 接着依次删边,如果删除的边不在该点最短路树上,那么就可以用预处理纪录的以该点为源点的最短距离

uva 1416 Warfare And Logistics (最短路树)

uva 1416 Warfare And Logistics Description The army of United Nations launched a new wave of air strikes on terrorist forces. The objective of the mission is to reduce enemy's logistical mobility. Each air strike will destroy a path and therefore inc

UVA 1416 - Warfare And Logistics(最短路树)

UVA 1416 - Warfare And Logistics 题目链接 题意:给定一个无向图,每个边一个正权,c等于两两点最短路长度之和,现在要求删除一边之后,新图的c值最大的是多少 思路:直接枚举删边,每次做一次dijkstra的话复杂度太高,其实如果建好最短路树,如果删去的边在最短路树上,才需要去做,这样复杂度就优化到(n^2mlog(n)),勉强可以接受 代码: #include <cstdio> #include <cstring> #include <vecto

UVALive 4080 Warfare And Logistics

本题最关键的地方在于,对于一个单源的最短路径来说,如果最短路树上的边没有改变的话,那么最短路肯定是不会变的, 所以只要枚举删掉最短路树上的边.这样的时间复杂度就能过了. 瞎搞真删边,结果T了... #include<bits/stdc++.h> using namespace std; const int maxn = 102, maxm = 2002; int head[maxn], to[maxm], nxt[maxm],wei[maxm],ecnt; int delta[maxm]; v

训练指南 UVALive - 4080(最短路Dijkstra + 边修改 + 最短路树)

layout: post title: 训练指南 UVALive - 4080(最短路Dijkstra + 边修改 + 最短路树) author: "luowentaoaa" catalog: true mathjax: true tags: - Dijkstra - 最短路树 - 图论 - 训练指南 Warfare And Logistics UVALive - 4080 题意 ①先求任意两点间的最短路径累加和,其中不连通的边权为L ②删除任意一条边,求全局最短路径和的最大值 题解

la4080 Warfare And Logistics 罗列+最短

为了图.计算最短随机分ans1.和删除边缘.免费才能够获得最大和短路之间的最大分ans2,如果这两个不沟通.看作是两个点之间的最短距离l. 第一个想法是枚举每个边缘,然后运行n最短时间.但是,这种复杂性是1000*1000*100*log(100),太大了..事实上在固定起点,求出单元最短路的时候.同一时候能够求出单源最短路树,仅仅有删除的边在树上的时候.源点到任一点的最短路才会有变化,所以在每次跑单源最短路的时候,仅仅须要枚举树上的n-1条边就能够了.累加一下删除每一条边时,在当前源点的情况下

UVA 4080 Warfare And Logistics 战争与物流 (最短路树,变形)

题意:给一个无向图,n个点,m条边,可不连通,可重边,可多余边.两个问题,第一问:求任意点对之间最短距离之和.第二问:必须删除一条边,再求第一问,使得结果变得更大. 思路: 其实都是在求最短路的过程. 第一问可以floyd解决,也可以SSSP解决.注意是任意两个点,(a,b)和(b,a)是不同的,都要算. 第二问要穷举删除每条边,再求第一问.为了降低复杂度,假设用dijkstra求最短路,那么可以利用第一问中所生成的树,共n棵,每棵至多n-1条边,如果穷举的边不在该某树上,那么该树的所有路径长不

Warfare And Logistics UVALive - 4080 (最短路树)

Warfare And Logistics UVALive - 4080 题意:给n个点m条边.令c为每对节点的最短路长度之和.要求删除一条边后使得新的c值c'最大,不连通的两点对短路视为L. [如果每次删除一条边,要跑m次dijkstra,其实其中很多次都对最短路没有影响,因为删掉的边不在最短路里] [因此,可以每次删除最短路树中的一条边,需要跑n次,复杂度降低到可接受程度] 1 #include <bits/stdc++.h> 2 #define LL long long 3 using

UVA 1416 最短路树

Warfare And Logistics The army of United Nations launched a new wave of air strikes on terroristforces. The objective of the mission is to reduce enemy's logistical mobility. Each airstrike will destroy a path and therefore increase the shipping cost