UVA 4080 Warfare And Logistics 战争与物流 (最短路树,变形)

 

 

 

题意:给一个无向图,n个点,m条边,可不连通,可重边,可多余边。两个问题,第一问:求任意点对之间最短距离之和。第二问:必须删除一条边,再求第一问,使得结果变得更大。

 

思路:

  其实都是在求最短路的过程。

  第一问可以floyd解决,也可以SSSP解决。注意是任意两个点,(a,b)和(b,a)是不同的,都要算。

  第二问要穷举删除每条边,再求第一问。为了降低复杂度,假设用dijkstra求最短路,那么可以利用第一问中所生成的树,共n棵,每棵至多n-1条边,如果穷举的边不在该某树上,那么该树的所有路径长不变,不必计算,否则需要计算。所以需要记录路径,并将整棵树的边集存起来,同时保存每棵树的任意两点路径之和。

  用结构体可以解决重边,问题应该不多,要注意各种细节,错了就重新打,也许更快。

  

 

  1 #include <bits/stdc++.h>

  2 #define LL long long

  3 #define pii pair<int,int>

  4 #define INF 0x7f7f7f7f

  5 using namespace std;

  6 const int N=220;

  7 int n, m, l, edge_cnt;

  8 vector<int> vect[N];

  9 

 10 struct node

 11 {

 12     int from, to, dis,tag;

 13     node(){};

 14     node(int from,int to,int dis,int tag):from(from),to(to),dis(dis),tag(tag){};

 15 }edge[2050];

 16 

 17 void add_node(int from,int to,int dis,int tag)

 18 {

 19     edge[edge_cnt]=node(from, to, dis, tag);

 20     vect[from].push_back(edge_cnt++);

 21 }

 22 

 23 int dist[N], vis[N], path[N];

 24 LL dijkstra(int s)

 25 {

 26     memset(dist,0x7f,sizeof(dist));

 27     memset(vis,0,sizeof(vis));

 28     for(int i=0; i<=n; i++) path[i]=-1;

 29 

 30     priority_queue<pii,vector<pii>,greater<pii> >   que;

 31     dist[s]=0;

 32     que.push(make_pair(0,s));

 33 

 34     while(!que.empty())

 35     {

 36         int x=que.top().second;que.pop();

 37         if(vis[x])  continue;

 38         vis[x]=1;

 39         for(int i=0; i<vect[x].size(); i++)

 40         {

 41             node e=edge[vect[x][i]];

 42             if(e.tag>0 && dist[e.to]>dist[e.from]+e.dis )

 43             {

 44                 path[e.to]=vect[x][i];

 45                 dist[e.to]=dist[e.from]+e.dis;

 46                 que.push(make_pair(dist[e.to], e.to));

 47             }

 48         }

 49     }

 50 

 51     LL sum=0;

 52     for(int i=1; i<=n; i++ )

 53     {

 54         if(dist[i]>=INF)    sum+=l;//不可达的,按L算

 55         else    sum+=dist[i];

 56     }

 57     return sum;

 58 }

 59 

 60 LL ans1[N];

 61 int cal()

 62 {

 63     memset(ans1,0,sizeof(ans1));

 64     LL  first=0;

 65     unordered_set<int> tree[N];

 66     for(int i=1; i<=n; i++)

 67     {

 68         ans1[i]=dijkstra(i);

 69         first+=ans1[i];

 70         //收集边

 71         for(int k=1; k<=n; k++)

 72         {

 73             if(path[k]>=0)//注意如何初始化

 74             {

 75                 tree[i].insert(path[k]);

 76                 tree[i].insert(path[k]^1);

 77             }

 78         }

 79     }

 80     //另一个问

 81     LL second=0;

 82     for(int i=0; i<edge_cnt; i+=2)

 83     {

 84         edge[i].tag=edge[i+1].tag=0;

 85         LL sum=0;

 86         for(int j=1; j<=n; j++)

 87         {

 88             if( tree[j].find(i)==tree[j].end() )  //是点j的树上,要重新算

 89                 sum+=ans1[j];

 90             else

 91                 sum+=dijkstra(j);

 92         }

 93         second=max(second, sum);

 94         edge[i].tag=edge[i+1].tag=1;

 95     }

 96     printf("%lld %lld\n", first, second );//仅1个空格

 97 }

 98 

 99 int main()

100 {

101     freopen("input.txt", "r", stdin);

102     int a, b, c;

103     while(scanf("%d%d%d", &n, &m, &l)==3)

104     {

105         edge_cnt=0;

106         memset(edge,0,sizeof(edge));

107         for(int i=0; i<=n; i++) vect[i].clear();

108         for(int i=0; i<m; i++)

109         {

110             scanf("%d%d%d",&a,&b,&c);

111             if(a==b)    continue;

112             add_node(a,b,c,1);

113             add_node(b,a,c,1);

114         }

115         cal();

116     }

117     return 0;

118 }
AC代码

 

你可能感兴趣的:(log)