5 4 5 1 1 3 3 2 5 4 2 2 1 2 1 2
INF INF INF INF 2 2
题意:每次只能删除一条边,问每个点到所有点的最短路径总和最小。只要任意两个点之间没有路的就输出 INF。
#include<stdio.h> #include<queue> using namespace std; const int N = 105; const int inf = 99999999; struct EDG { int u,v,id; }; vector<EDG>mapt[N]; int dis[N],n,numEdg[N][N],father[N],goEdg[N][N][N],sum[N]; void spfa(int id,int s,bool b) { queue<int>q; int inq[N]={0}; for(int i=1;i<=n;i++) dis[i]=inf; q.push(s); dis[s]=0; father[s]=s; while(!q.empty()) { s=q.front(); q.pop(); inq[s]=0; int len=mapt[s].size(); for(int i=0;i<len;i++) if(id!=mapt[s][i].id) { int v=mapt[s][i].v; if(dis[v]>dis[s]+1) { dis[v]=dis[s]+1; if(b) father[v]=s; if(inq[v]==0) inq[v]=1,q.push(v); } } } } int main() { int m,a,b; EDG ss,edg[N*30]; while(scanf("%d%d",&n,&m)>0) { for(int i=1;i<=n;i++) { mapt[i].clear(); for(int j=1;j<=n;j++) { numEdg[i][j]=0; for(int e=1;e<=n;e++) goEdg[i][j][e]=0; } } for(int i=1;i<=m;i++) { scanf("%d%d",&a,&b); edg[i].u=a; edg[i].v=b; numEdg[a][b]++; numEdg[b][a]++; if(numEdg[a][b]>1) continue; ss.id=i; ss.v=b; mapt[a].push_back(ss); ss.v=a; mapt[b].push_back(ss); } int SUM=0; for(int i=1;i<=n;i++) { spfa(-1,i,true); sum[i]=0; for(int j=1;j<=n;j++) if(dis[j]==inf) { sum[i]=inf; break; } else sum[i]+=dis[j]; if(sum[i]==inf) { SUM=inf; break; } SUM+=sum[i]; for(int j=1;j<=n;j++) { int u,v=j; while(father[v]!=v) { u=father[v]; goEdg[i][u][v]=goEdg[i][v][u]=1; v=u; } } } int ans; for(int id=1;id<=m;id++) { if(SUM==inf) { printf("INF\n"); continue; } else if(numEdg[edg[id].u][edg[id].v]>1) { printf("%d\n",SUM); continue; } ans=0; for(int i=1;i<=n;i++) if(goEdg[i][edg[id].u][edg[id].v])//最主要的优化 { spfa(id,i,false); for(int j=1;j<=n;j++) if(dis[j]==inf) { ans=inf; break; } else ans+=dis[j]; if(ans==inf) break; } else ans+=sum[i]; if(ans==inf) printf("INF\n"); else printf("%d\n",ans); } } }
原文地址:http://blog.csdn.net/u010372095/article/details/45115679