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 increase the shipping cost of the shortest path between two enemy locations. The maximal damage is always desirable.
Let's assume that there are n enemy locations connected bym bidirectional paths, each with specific shipping cost. Enemy's total shipping cost is given asc = path(i,j) . Here path(i, j) is the shortest path between locationsi and j . In casei and j are not connected,path(i, j) = L . Each air strike can only destroy one path. The total shipping cost after the strike is noted asc' . In order to maximized the damage to the enemy, UN's air force try to find the maximalc' - c .
The first line ofeach input case consists ofthree integers: n , m , and L . 1 < n100 ,1m1000 , 1L108 . Each ofthe following m lines contains three integers:a , b , s , indicating length of the path between a andb .
For each case, output the total shipping cost before the air strike and the maximal total shipping cost after the strike. Output them in one line separated by a space.
4 6 1000 1 3 2 1 4 4 2 1 3 2 3 3 3 4 1 4 2 2
28 38
这题过的真艰辛!从昨晚搞到现在,最后写个数据生成程序+别人ac的代码,生成了点数据才发现错在哪儿了
本题关键就是记录下每条边是属于哪些棵生成树,然后删边后重新计算相应的变化。
但是,如果开始时就没有一颗最短路的生成树(即图不连通),那我们就需要特别注意了(我就是wa在这个地方被搞死了啊)
开始时还犯了个sb错误,把边的最大数目搞错了(导致数组开小,无限re)
因为是无向图,所以用模版加边时每条边加了两次,所以最后总边数是乘以2了的
还有如果数据给出了一条类似a->a的边,输入应该直接跳过
关于这道题还有一个拓展:
假如这道题改为如果之后输入m条边,要求计算添加了某条边的最小值。
当然还是可以用本题的方法去做,但实际上面对这个问题还有一个更好的方法。
如果你深入理解了floyed这个动态规划的算法,在面对这个题其实也是可以应用的。
也是抓住影响的只有与改变的那条边相关的最短路。
首先Floyd求出任意两点间的最短距离,之后关键是每更新一条边该如何维护这些最短距离。
假设用floyd求出来后的答案存在矩阵map[n][n]里,对于每次更新(a[i][j]=k),如果a[i][j]>=map[i][j],则不用更新;
否则,对于map[x][y],需要更新的只有两种情况,一种是从x->i->j->y,另一种是x->j->i->y,选出这两种的最小的与当前的map[x][y]比较即可。
因此只需要枚举x,y,然后更新map[x][y],总复杂度为O(n^3+m*n^2),比用dijkstra要好一些
floyed不能用在本题的原因是,原来的边被删掉,而导致边长变大,这样是无法处理的。
代码如下:
#include <cstdio> #include <cstring> #include <algorithm> #include <vector> #include <queue> using namespace std; typedef long long LL; const int maxn = 100 + 5; const int INF = 1000000000; struct Edge{ int from,to; LL dist; int tag;//XiuGai }; 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];//每个节点出发的边编号(从0开始) bool done[maxn];//是否已永久编号 int d[maxn];//s到各个点的距离 int p[maxn];//最短路中的上一条边 vector<int> mark[2005]; LL l; void init(int n,LL l){ this->n = n; for(int i = 0;i < n;i++) G[i].clear();//清空邻接表 edges.clear();//清空边表 for(int i = 0;i < 1005;i++) mark[i].clear(); for(int i = 0;i < maxn;i++) p[i] = -1; this->l = l; } void AddEdge(int from,int to,LL dist,int tag){ //如果是无向图,每条无向边需调用两次AddEdge edges.push_back((Edge){from,to,dist,tag}); m = edges.size(); G[from].push_back(m-1);//(m-1)因为边从0开始编号 } 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)); 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++){ Edge& e = edges[G[u][i]]; if(e.tag == 0) continue;//XiuGai 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 ret = 0; for(int i = 0;i < n;i++){ if(i == s) continue; if(d[i] == INF) ret += l; else ret += d[i]; } return ret; } void track(int s){ for(int i = 0;i < n;i++){ if(i == s) continue; if(p[i] == -1) continue; mark[p[i]].push_back(s); } } void fuckedge(int n){ edges[n].tag = 0; if(edges[n].from == edges[n+1].to && edges[n].dist == edges[n+1].dist && edges[n].to == edges[n+1].from) edges[n+1].tag = 0; else edges[n-1].tag = 0; } void recover(int n){ edges[n].tag = 1; if(edges[n].from == edges[n+1].to && edges[n].dist == edges[n+1].dist && edges[n].to == edges[n+1].from) edges[n+1].tag = 1; else edges[n-1].tag = 1; } }; Dijkstra solver; LL ans[maxn]; LL c,c2; int main(){ //freopen("a","r",stdin); //freopen("A1","w",stdout); int n,m,l; int a,b,s; while(scanf("%d%d%d",&n,&m,&l) != EOF){ solver.init(n,l); c = 0; while(m--){ scanf("%d%d%d",&a,&b,&s);a--;b--; if(a == b) continue; solver.AddEdge(a,b,s,1);solver.AddEdge(b,a,s,1); } for(int i = 0;i < n;i++){ c += ans[i] = solver.dijkstra(i); solver.track(i); } c2 = c;LL tem; for(int i = 0;i < solver.edges.size();i++){ solver.fuckedge(i); if(i%2==0) tem = c; for(int j = 0;j < solver.mark[i].size();j++){ tem -= ans[solver.mark[i][j]]; tem += solver.dijkstra(solver.mark[i][j]); } solver.recover(i); c2 = max(c2,tem); } printf("%lld %lld\n",c,c2); } return 0; }
生成数据
#include <cstdio> #include <cstdlib> #include <time.h> int main(){ srand((int)time(NULL)); freopen("a","w",stdout); for(int i = 0;i < 5;i++){ int n,m; printf("%d %d %d\n",n = rand()%5+2,m = rand()%10+1,rand()%1000000); while(m--){ printf("%d %d %d\n",rand()%n+1,rand()%n+1,rand()%10000); } printf("\n\n"); } return 0; }