UVA1416 Warfare And Logistics

链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=36232

【题意】

给出一个无向图,定义C =∑(d[i][j])  ,其中d[][]表示两点间的最短距离,求出C并求出删除一条边后的最大C2。

【思路】

最短路树。

简单地想我们可以用SPFA求出每一个节点到另一个节点的最短距离,然后枚举删除m条边再次进行这项工作。

其实这里我们不用重新全部计算,因为如果所删除的边不在scr的最短路树上,那么这棵树不会被破坏。因此我们可以提前在求C的时候记录每一个scr最短路树上的边以及这棵最短路树的总权值,依旧枚举删边,判断是否需要重新计算即可。

需要注意的是有重边的时候应该用次短边代替。

【代码】

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<queue>
  4 #include<vector>
  5 #include<algorithm>
  6 #define FOR(a,b,c) for(int a=(b);a<=(c);a++)
  7 using namespace std;
  8
  9 const int maxn = 100+10,maxm=1000+10;
 10 const int INF=1e9;
 11 struct Edge{
 12     int u,v,w,next;
 13 };
 14
 15 int n,m,L;
 16
 17 struct SPFA{
 18     int n;
 19     Edge e[2*maxm];
 20     int en,front[maxn];
 21     int inq[maxn],d[maxn];
 22     int p[maxn];
 23     queue<int> q;
 24
 25     void init(int n){
 26         this->n=n;
 27         en=-1;
 28         memset(front,-1,sizeof(front));
 29     }
 30     void AddEdge(int u,int v,int w) {
 31          en++; e[en].u=u; e[en].v=v; e[en].w=w; e[en].next=front[u]; front[u]=en;
 32     }
 33     void solve(int s) {
 34         memset(inq,0,sizeof(inq));
 35         memset(p,0,sizeof(p));
 36         for(int i=1;i<=n;i++) d[i]=INF;
 37
 38         d[s]=0; inq[s]=1; q.push(s);
 39         while(!q.empty()) {
 40             int u=q.front(); q.pop(); inq[u]=0;
 41             for(int i=front[u];i>=0;i=e[i].next) {
 42                 int v=e[i].v,w=e[i].w;
 43                 if(w>0 && d[v]>d[u]+w) {         //w<0表示此边已断
 44                     d[v]=d[u]+w;
 45                     p[v]=i;
 46                     if(!inq[v]) {
 47                         inq[v]=1;
 48                         q.push(v);
 49                     }
 50                 }
 51             }
 52         }
 53     }
 54 }spfa;
 55
 56 vector<int> gr[maxn][maxn];  //保存ij之间所有的边
 57 int idx[maxn][maxn];         //边ij在SPFA中对应的编号
 58 int used[maxn][maxn][maxn];  //used[scr][u][v]表示在scr为根的最短路树上边uv是否出现
 59 int sum_single[maxn];        //scr的最短路树的d[]之和
 60
 61 int CALC_C() {
 62     int ans=0;
 63     memset(used,0,sizeof(used));
 64     FOR(scr,1,n)
 65     {
 66         spfa.solve(scr);
 67         sum_single[scr]=0;
 68         FOR(v,1,n)
 69         {
 70            if(v!=scr) {
 71                    int u=spfa.e[spfa.p[v]].u;
 72                    used[scr][u][v]=used[scr][v][u]=1;
 73            }
 74            sum_single[scr] += spfa.d[v]==INF? L : spfa.d[v];
 75         }
 76         ans += sum_single[scr];
 77     }
 78     return ans;
 79 }
 80 int CALC_C2(int a,int b) {
 81     int ans=0;
 82     FOR(scr,1,n)
 83     {
 84           if(!used[scr][a][b]) ans+=sum_single[scr];
 85           //如果边ij没有出现在i的最短路树上则无须重新计算
 86           else
 87           {
 88                 spfa.solve(scr);
 89                 FOR(v,1,n) ans += spfa.d[v]==INF?L: spfa.d[v];
 90           }
 91     }
 92     return ans;
 93 }
 94
 95 int main()
 96 {
 97     while(scanf("%d%d%d",&n,&m,&L)==3)  //==3 否则会TLE
 98     {
 99         int u,v,w;
100         spfa.init(n);
101         FOR(i,1,n) FOR(j,1,n) gr[i][j].clear();
102         while(m--) {
103             scanf("%d%d%d",&u,&v,&w);
104             gr[u][v].push_back(w);
105             gr[v][u].push_back(w);
106         }
107         FOR(i,1,n) FOR(j,i+1,n) if(!gr[i][j].empty()){
108             sort(gr[i][j].begin(),gr[i][j].end());
109             spfa.AddEdge(i,j,gr[i][j][0]);
110             idx[i][j]=spfa.en;
111             spfa.AddEdge(j,i,gr[i][j][0]);
112             idx[j][i]=spfa.en;
113         }
114         int c=CALC_C(),c2=-1;
115         FOR(i,1,n) FOR(j,i+1,n) if(!gr[i][j].empty()){
116             int& e1=spfa.e[idx[i][j]].w;
117             int& e2=spfa.e[idx[j][i]].w;
118             if(gr[i][j].size()==1) e1=e2=-1;
119             else e1=e2=gr[i][j][1];          //用次短边代替
120             c2=max(c2,CALC_C2(i,j));         //"删除" ij之间的边之后计算c2
121             e1=e2=gr[i][j][0];
122         }
123         printf("%d %d\n",c,c2);
124     }
125     return 0;
126 }
时间: 2024-11-13 06:53:21

UVA1416 Warfare And Logistics的相关文章

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 (最短路)

Description 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 of the sh

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(最短路树)

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

【UVA1416】(LA4080) Warfare And Logistics (单源最短路)

题目: Sample Input4 6 10001 3 21 4 42 1 32 3 33 4 14 2 2Sample Output28 38 题意: 给出n个节点m条无向边的图,每条边权都为正.令c等于每对结点的最短路长度之和.要求删一条边后使得新的c值c‘最大.不连通两点的最短路长度视为L.(1<=n<=100,1<=m<=1000,1<=L<=10^8) 分析: 因为规模比较小,所以可以考虑删边.主要是删什么边的问题. 这里用到最短路树.在源点确定的情况下,只要

UVA1416/LA4080 Warfare And Logistics

题目大意:有N个点,M条路,如果两条路不连通的话,就将这两条路的距离设置为L 现在要求你求出每两点之间的最短距离和 接着要求 求出炸断 给出的M条路中的一条路后,每两点之间的最短距离和的最大值(翻译来自http://blog.csdn.net/l123012013048/article/details/47297393) 单源最短路树:把源点到其他点的最短路拼起来,形成最短路树(可能有多棵,这里只需要一棵).我们把起点为i的单源最短路树称为i源最短路树.想要让最短路改变,删除的边必定在这课最短路

Warfare And Logistics UVA - 1416

题目链接:https://vjudge.net/problem/UVA-1416 题解: 这是一个最短路的好题,首先我们考虑如果暴力弗洛伊德,显然时间复杂度不对,如果做n次spfa好像复杂度也不对,所以考虑优化这个暴力. 我们考虑对于一个单源最短路,只有改变了最短路树中的某条边,才需要重新做一次最短路.所以我们不需要对于每条边都重新做最短路,只需要对于在最短路数上的边做,所以时间复杂度就优化成了你] mn^2log(n). 实现的时候要用pre数组记下,以i为终点的最短路树的边,实现有点复杂,看

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

la4080 Warfare And Logistics 罗列+最短

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