UVALive 4080 Warfare And Logistics

题意:给定一个n节点m条边的无向图,定义c为每对顶点的最短路之和,要求删掉一条边重新求一个c值c',求出c'最大值.

解法:dijkstra+堆优化,最短路径树.

  首先可以通过dijkstra求出单源最短路,对于删边的操作,如果我们枚举每条边的时候都求一次最短路肯定是超时的.

  对于一个源点确定的最短路径树,如果我们删掉的边不在这个最短路径树上,那么就不需要重新计算最短路.

  根据这个性质,我们只需要记录下每个源点构成的最短路径树上都有哪条边,然后在枚举边的时候判断是否需要重新计算最短路

 1 #include<cstdio>
 2 #include<queue>
 3 #include<iostream>
 4 #include<cstring>
 5 #include<algorithm>
 6 #define N 3010
 7 using namespace std;
 8 typedef long long ll;
 9 struct Edge{
10     int u,v,len,next;
11 }edge[N];
12 struct heap{
13     int dis,id,pre;
14     bool operator < (const heap &a)const{
15         return dis > a.dis;
16     }
17 };
18 int head[N],cnt,dis[N],n,m,l;
19 bool used[N],hash[N];
20 ll ans[N],sum[N][N];
21 void init(){
22     cnt=0;
23     memset(head,-1,sizeof(head));
24     memset(hash,0,sizeof(hash));
25     memset(ans,0,sizeof(ans));
26 }
27 void addedge(int u,int v,int len){
28     edge[cnt].u=u;edge[cnt].v=v;
29     edge[cnt].len=len;
30     edge[cnt].next=head[u];
31     head[u]=cnt++;
32 }
33 ll dijkstra(int s,int f1,int f2){
34     priority_queue<heap>Q;
35     memset(used,0,sizeof(used));
36     for(int i=1;i<=n;i++)dis[i]=l;
37     heap p;
38     p.dis=0,p.id=s,p.pre=-1;
39     dis[s]=0;
40     Q.push(p);
41     while(!Q.empty()){
42         p=Q.top();Q.pop();
43         if(used[p.id])continue;
44         used[p.id]=1;
45         if(f1==cnt&&f2==cnt&&p.id!=s)
46             hash[p.pre]=hash[p.pre^1]=1;
47         for(int k=head[p.id];k!=-1;k=edge[k].next){
48             if(k==f1||k==f2)continue;
49             int u=edge[k].u,v=edge[k].v,len=edge[k].len;
50             if(dis[v]>dis[u]+len){
51                 dis[v]=dis[u]+len;
52                 heap q;
53                 q.id=v,q.dis=dis[v],q.pre=k;
54                 Q.push(q);
55             }
56         }
57     }
58     ll sum=0;
59     for(int i=1;i<=n;i++)
60         sum+=dis[i];
61     return sum;
62 }
63 
64 int main(){
65     while(~scanf("%d%d%d",&n,&m,&l)){
66         init();
67         for(int i=0;i<m;i++){
68             int a,b,c;
69             scanf("%d%d%d",&a,&b,&c);
70             addedge(a,b,c);
71             addedge(b,a,c);
72         }
73         for(int i=1;i<=n;i++){
74             memset(hash,0,sizeof(hash));
75             sum[i][cnt]=dijkstra(i,cnt,cnt);
76             for(int j=0;j<cnt;j++){
77                 if(hash[j]==0)sum[i][j]=sum[i][cnt];
78                 else sum[i][j]=dijkstra(i,j,j^1);
79             }
80         }
81         ll ans1=0,ans2=0;
82         for(int j=0;j<cnt;j++){
83             ll all=0;
84             for(int i=1;i<=n;i++)
85                 all+=sum[i][j];
86             ans2=max(ans2,all);
87         }
88         for(int i=1;i<=n;i++){
89             ans1+=sum[i][cnt];
90         }
91         printf("%lld %lld\n",ans1,ans2);
92     }
93     return 0;
94 }

转载于:https://www.cnblogs.com/silver-bullet/archive/2012/11/28/2792221.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值