La 4080 Warfare and logistics Dijkstra
2016-07-21 21:01
399 查看
题目大意:
给定n个点,m条边的无向图, 定义c为任意两点间的最短路之和,
即 c=∑w(i,j)|i∈V,j∈V
求初始时的c与删去任意一条边后的c’的最大值。
分析:
对于最初始时的c, 我们可以通过每次计算以某个点为源点的最短路径,不难发现,每次计算后的距离和就是初始值c。
每一次进行删边操作时,就可以枚举每一条边进行决策:删除或者不删除,对于删除的边,如果它不在以某个点为源点的Dijkstra树上,那么删除它对于最短路径的长度就不会造成影响,所以我们可以忽略它,直接利用上一次计算初始c值时的答案即可。这样可以使时间复杂度变得可以令人接受。
代码:
给定n个点,m条边的无向图, 定义c为任意两点间的最短路之和,
即 c=∑w(i,j)|i∈V,j∈V
求初始时的c与删去任意一条边后的c’的最大值。
分析:
对于最初始时的c, 我们可以通过每次计算以某个点为源点的最短路径,不难发现,每次计算后的距离和就是初始值c。
每一次进行删边操作时,就可以枚举每一条边进行决策:删除或者不删除,对于删除的边,如果它不在以某个点为源点的Dijkstra树上,那么删除它对于最短路径的长度就不会造成影响,所以我们可以忽略它,直接利用上一次计算初始c值时的答案即可。这样可以使时间复杂度变得可以令人接受。
代码:
#include<bits/stdc++.h> using namespace std; const int maxn = 100 + 10; const int inf = 0x7fffffff; struct edge { int from, to, dist; }; 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 dis[maxn], pre[maxn]; void init(int n) { this->n = n; for(int i=0; i<n; i++) G[i].clear(); edges.clear(); } void add_edge(int from, int to, int dist) { edges.push_back((edge){from, to, dist}); m = edges.size(); G[from].push_back(m-1); } //get the single-source shortest path from s void dijkstra(int s) { priority_queue<Heapnode> q; for(int i=0; i<n; i++) dis[i] = inf; dis[s] = 0; memset(done, false, sizeof(done)); 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<(int)G[u].size(); i++) { edge& e = edges[G[u][i]]; if(e.dist > 0 && dis[e.to] > dis[u] + e.dist) { dis[e.to] = dis[u] + e.dist; pre[e.to] = G[u][i]; q.push((Heapnode){dis[e.to], e.to}); } } } } }Dij; int n, m, L, u, v, w; vector<int> gr[maxn][maxn]; bool used[maxn][maxn][maxn]; // in the shortest path from src, the edge u->v wheather or not used int idx[maxn][maxn]; //the number in the Dij structure int sum_single[maxn]; int compute_c() { int ans = 0; memset(used, false, sizeof(used)); for(int src=0; src < n; src++) { Dij.dijkstra(src); sum_single[src] = 0; for(int i=0; i<n; i++) { if(i != src) { int fa = Dij.edges[Dij.pre[i]].from; used[src][i][fa] = used[src][fa][i] = 1; }sum_single[src] += Dij.dis[i] == inf ? L : Dij.dis[i]; }ans += sum_single[src]; } return ans; } int compute_newc(int a, int b) { int ans = 0; for(int src=0; src < n; src++) { if(!used[src][a][b]) ans += sum_single[src]; else { Dij.dijkstra(src); for(int i=0; i<n; i++) ans += Dij.dis[i] == inf ? L : Dij.dis[i]; } } return ans; } int main() { #ifndef ONLINE_JUDGE freopen("data.txt", "r", stdin); freopen("ans.txt", "w", stdout); #endif a92d while(scanf("%d%d%d", &n, &m, &L) == 3 && n) { Dij.init(n); for(int i=0; i<n; i++) for(int j=0; j<n; j++) gr[i][j].clear(); for(int i=0; i<m; i++) { scanf("%d%d%d", &u, &v, &w); u--, v--; gr[u][v].push_back(w); gr[v][u].push_back(w); } for(int i=0; i<n; i++) for(int j=i+1; j<n; j++) if(!gr[i][j].empty()) { sort(gr[i][j].begin(), gr[i][j].end()); Dij.add_edge(i, j, gr[i][j][0]); idx[i][j] = Dij.m - 1; Dij.add_edge(j, i, gr[i][j][0]); idx[j][i] = Dij.m - 1; } int c = compute_c(); int c1 = -1; for(int i=0; i<n; i++) for(int j=i+1; j<n; j++) if(!gr[i][j].empty()) { int& e1 = Dij.edges[idx[i][j]].dist; int& e2 = Dij.edges[idx[j][i]].dist; if(gr[i][j].size() == 1) e1 = e2 = -1; else e1 = e2 = gr[i][j][1]; c1 = max(c1, compute_newc(i, j)); e1 = e2 = gr[i][j][0]; } printf("%d %d\n", c, c1); } return 0; }
相关文章推荐
- 如何组织构建多文件 C 语言程序(二)
- 如何写好 C main 函数
- Lua和C语言的交互详解
- 关于C语言中参数的传值问题
- 简要对比C语言中三个用于退出进程的函数
- 深入C++中API的问题详解
- 基于C语言string函数的详解
- C语言中fchdir()函数和rewinddir()函数的使用详解
- C语言内存对齐实例详解
- C语言编程中统计输入的行数以及单词个数的方法
- C 语言简单加减乘除运算
- C语言自动生成enum值和名字映射代码
- C语言练习题:自由落体的小球简单实例
- 使用C语言判断英文字符大小写的方法
- c语言实现的带通配符匹配算法
- C语言实现顺序表基本操作汇总
- C语言中进制知识汇总
- C语言判断一个数是否是2的幂次方或4的幂次方
- C语言二进制思想以及数据的存储
- C语言中计算正弦的相关函数总结