题目大概是说有n个顶点,m条边,然后按顺序删除这m条边,每次删除一条边,计算下一条边时前面被删除的边重新恢复,每次计算n个顶点通过m-1条边到其余n-1个顶点的的最短路之和。
不优化,直接删一条边算n次SPFA的话,TLE。这里可以通过优化,来减少时间。
优化点:
预处理:在删边之前先算一次每个顶点到n-1个最短路之和 保存至num[i]中(i为顶点编号)总和保存sum中,用pre[i][v]=u(顶点编号)记录计算i最短路时路径<u,v>,用mark[u][v][0](等于1或者0)来记录<u,v>是否在计算中出现过。
然后删除边<u,v>处理。
1.如果num[i]出现INF,直接INF(不删都到不了,删了更到不了);
2.如果有重边,那么你删一条,后面还有,删边不影响,直接输出sum;
3.没有重边:
1.如果<u,v>没有在计算sum中出现过(mark[u][v][0]),即都没有出现在任何n个顶点的最短路径中,那么删去<u,v>不影响,直接输出sum;
2.重新计算最短路和sum:
1.如果在计算第i个顶点到其它点最短路时,pre[i][u]!=v并且pre[i][v]!=u,即<u,v>没有出现在预处理的最短路径中,直接sum+=num[i];
2.<u,v>出现在预处理最短路径中,只能重新计算Spfa(i),sum+=Spfa(i)(Spfa(i)返回的是i顶点到其余顶点的最短路之和),如果有Spfa(i)=INF,结束计算循 环,输出INF,没有的话最后输出sum。
刚开始没有想到3.2.1这个优化点,直接TLE,说明这点优化相当重要。
还有我在网上看到别人说3.2.2中计算sum时 sum+=Spfa(u)-num[u]+Spfa(v)-num[v],没看明白,怎么证明这个公式??
SPFA:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define MAX_VERTEX 110
#define INF 0x3f3f3f3f
int map[MAX_VERTEX][MAX_VERTEX],visit[MAX_VERTEX],q[MAX_VERTEX],dis[MAX_VERTEX];
int pre[MAX_VERTEX][MAX_VERTEX];
int mark[MAX_VERTEX][MAX_VERTEX][5];
int num[MAX_VERTEX];
int aa[3010],bb[3010];
int vex,arc,sum;
int flag;
int Spfa(int s)
{
int rear,front,i,pos;
int sum1,sum2,vexnum;
memset(visit,0,sizeof(visit));
memset(dis,0x3f,sizeof(dis));
memset(q,0,sizeof(q));
rear=front=0;
q[rear]=s;
visit[s]=1;
rear++;
dis[s]=0;
sum1=0;
// sum2=0;
//vexnum=0;
while(front<rear)
{
pos=q[front];
visit[pos]=0;
front++;
//sum2+=dis[pos];
//vexnum++;
for(i=1;i<=vex;i++)
{
if(i==pos) continue;
if(dis[i]>dis[pos]+1 && map[pos][i]>0)
{
dis[i]=dis[pos]+1;
if(flag==0)
{
pre[s][i]=pos;
mark[pos][i][flag]=mark[i][pos][flag]=1;
}
if(!visit[i])
{
q[rear]=i;
visit[i]=1;
rear++;
}
}
}
}
/* if(vexnum<vex) return INF;
else return sum2;*/
for(i=1;i<=vex;i++)
{
if(dis[i]==INF)
{
return INF;
break;
}
else sum1+=dis[i];
}
return sum1;
}
int main()
{
int i,j,sum2;
while(scanf("%d%d",&vex,&arc)!=EOF)
{
memset(map,0,sizeof(map));
memset(aa,0,sizeof(aa));
memset(bb,0,sizeof(bb));
memset(pre,0,sizeof(pre));
memset(num,0,sizeof(num));
memset(mark,0,sizeof(mark));
for(i=0;i<arc;i++)
{
scanf("%d%d",&aa[i],&bb[i]);
map[aa[i]][bb[i]]++;
map[bb[i]][aa[i]]++;
}
sum=0;
flag=0;
for(i=1;i<=vex;i++)
{
if(Spfa(i)==INF)
{
sum=INF;
break;
}
num[i]=Spfa(i);
sum+=num[i];
}
flag=1;
for(i=0;i<arc;i++)
{
if(sum==INF)
{
printf("INF\n");
continue;
}
map[aa[i]][bb[i]]--;
map[bb[i]][aa[i]]--;
if(map[aa[i]][bb[i]]>0)
{
printf("%d\n",sum);
map[aa[i]][bb[i]]++;
map[bb[i]][aa[i]]++;
}
else
{
sum2=0;
for(j=1;j<=vex;j++)
{
if(mark[aa[i]][bb[i]][0]==0)
{
printf("%d\n",sum);
}
if(pre[j][aa[i]]!=bb[i] && pre[j][bb[i]]!=aa[i])
{
sum2+=num[j];
}
else
{
sum2+=Spfa(j);
if(sum2==INF) break;
}
}
if(sum2<INF) printf("%d\n",sum2);
else
printf("INF\n");
map[aa[i]][bb[i]]++;
map[bb[i]][aa[i]]++;
}
}
}
return 0;
}