• UVA1416 Warfare And Logistics


    UVA1416 Warfare And Logistics

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

    【题意】

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

    【思路】

      最短路树。

      简单地想我们可以用floyd或SPFA求出两点间的最短距离,然后枚举删除m条边再次进行这项工作。

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

      理论上时间需要O(n^3),实践中应该能跑O(n^2)。

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

    【代码】

      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
    ",c,c2);
    124     }
    125     return 0;
    126 }
  • 相关阅读:
    Backbone学习之todos实现
    由$(this).attr('id')引出的一点感想
    JS类的实现
    JS设计模式之接口
    JS设计模式之工厂模式
    JS设计模式之序
    JS的继承
    you think you know javascript?
    js中的null和undefined
    作用域、闭包等概念的理解
  • 原文地址:https://www.cnblogs.com/lidaxin/p/4914450.html
Copyright © 2020-2023  润新知