链接: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