zoukankan      html  css  js  c++  java
  • LA4080最短路树的应用

      1 /*LA4080最短路树的应用
      2 这道题的目的就是让人去合理运用最短路算法中的信息?
      3 求两两点之间的距离之和,一般让人去想到Floyd,或者n次的DIJ,但是Floyd算法虽然精简,但是可用的信息比较少,一次就要n^3的复杂度,
      4 如果直接这样做,肯定会超时,然而dij就灵活的多,有的信息能重复使用。
      5 思想:
      6 1、从每个源点出发,会产生一个最短路树,即是除了根节点之外,每个节点只有一个前驱,这个符合dij路径的唯一性
      7 2、对于一条边,如果这条边不在这条树上,肯定不会影响这棵树根节点i的dij距离和
      8 3、如果在树上,则对于树的根结点,要重新算一次dij
      9 细节:因为我们在计算的时候,只是模拟的把其中的边删除,所以一定不要影响原图的信息
     10 */
     11 #include<iostream>
     12 #include<string.h>
     13 #include<stdio.h>
     14 #include<stdlib.h>
     15 #include<cmath>
     16 #include<algorithm>
     17 #include<queue>
     18 #include<stack>
     19 #include<set>
     20 #include<map>
     21 #define maxn 110
     22 #define maxe 2100
     23 #define INF 100000000
     24 using namespace std;
     25 int N,M,L;
     26 int C,NC;
     27 //set<int>Tree[maxn];//存储没课最短路树上的所有边
     28 bool Tree[maxn][maxe];
     29 int tot[maxn];//每个节点的单源最短距离之和
     30 int nextint(){int x;scanf("%d",&x);return x;}
     31 struct Edge
     32 {
     33     int u,v,dis;
     34 };
     35 struct Node
     36 {
     37     int d,u;
     38     bool operator<(const Node &x)const{
     39         return d>x.d;
     40     }
     41 };
     42 struct Dijkstra
     43 {
     44     int n,m;
     45     vector<Edge>edge;
     46     vector<int>G[maxn];
     47     bool vis[maxn];
     48     int d[maxn],p[maxn];
     49 
     50     void init(int n)
     51     {
     52         this->n=n;
     53         edge.clear();
     54         for(int i=0;i<=n;i++) G[i].clear();
     55     }
     56 
     57     void add(int u,int v,int c){
     58         edge.push_back((Edge){u,v,c});
     59         m=edge.size();
     60         G[u].push_back(m-1);
     61     }
     62 
     63     int dij(int s,int earse)//源点、应该删除的边earse和earse+1
     64     {
     65         memset(vis,0,sizeof(vis));
     66         for(int i=0;i<=n;i++) d[i]=INF;
     67         d[s]=0;
     68         priority_queue<Node>Q;
     69         Q.push((Node){0,s});
     70         while(!Q.empty()){
     71             Node x=Q.top();Q.pop();
     72             int u=x.u;
     73             if (vis[u]) continue;
     74             vis[u]=true;
     75             for(int i=0;i<G[u].size();i++)
     76             {
     77                 if (earse>=0&& ( G[u][i]==earse || G[u][i]==earse+1)) continue;//开始把变量弄错了啊
     78                 Edge &e=edge[G[u][i]];
     79                 if (d[e.v]>d[u]+e.dis){
     80                     d[e.v]=d[u]+e.dis;
     81                     p[e.v]=G[u][i];
     82                     Q.push((Node){d[e.v],e.v});
     83                 }
     84             }
     85         }
     86         if (earse>=0)
     87         {
     88             int tot=0;
     89             for(int i=1;i<=n;i++)
     90             {
     91                 if (i==s) continue;
     92                 if(d[i]<INF) tot+=d[i];else tot+=L;
     93             }
     94             return tot;
     95         }
     96         else
     97         {
     98             tot[s]=0;
     99             for(int i=1;i<=n;i++)
    100             {
    101                 if (i==s) continue;
    102                 if(d[i]<INF) tot[s]+=d[i];else tot[s]+=L;
    103             }
    104             for(int i=1;i<=n;i++)//树上有n-1条边
    105             {
    106                 if(i==s) continue;
    107                 Tree[s][p[i]]=true;
    108             }
    109             return -1;
    110         }
    111     }
    112 }Dij;
    113 void read()
    114 {
    115     Dij.init(N);
    116     for(int i=0;i<M;i++)
    117     {
    118         int u,v,d;
    119         u=nextint();v=nextint();d=nextint();
    120         Dij.add(u,v,d);
    121         Dij.add(v,u,d);
    122     }
    123 }
    124 void init_c()//每个点dij,记录tree,和tot[i]
    125 {
    126     memset(Tree,0,sizeof(Tree));
    127     C=0;
    128     for(int i=1;i<=N;i++) {Dij.dij(i,-2);C+=tot[i];}//-2:暂时没有要删除的边
    129 }
    130 void solve()
    131 {
    132     NC=0;
    133     for(int i=0;i<2*M;i+=2)//枚举每条边,记得是无向图,一条边,存储了两个
    134     {
    135         int T=0;
    136         for(int j=1;j<=N;j++)
    137         {
    138             if (Tree[j][i] || Tree[j][i+1]) T+=Dij.dij(j,i);//以j为源点的单源最短和,i是暂时删除的边
    139             else T+=tot[j];
    140         }
    141         NC=max(NC,T);
    142     }
    143     printf("%d %d
    ",C,NC);
    144 }
    145 int main()
    146 {
    147     while(cin>>N>>M>>L)
    148     {
    149         read();
    150         init_c();
    151         solve();
    152     }
    153 }
  • 相关阅读:
    做事要趁早
    软件企业利润率知多少
    项目管理经验谈之意外事件处理
    App中调用iPhone的home + 电源键截屏功能
    WCF学习(一)
    10月博客学习一览
    设计模式之工厂模式读后感
    请教各位大鸟(关于附件上传)
    刚来的兄弟,一起扬帆起航吧
    巧用asp导出csv格式excel报表
  • 原文地址:https://www.cnblogs.com/little-w/p/3587957.html
Copyright © 2011-2022 走看看