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