題目大意:
有一個n(
多組數據
題目分析:
最暴力的方法就是刪掉每一條邊,然後枚舉每一個點,跑一邊bfs,時間複雜度O(nm^2)
據說會TLE誒O(∩▽∩)O
於是看了大家的博客,知道了有最短路徑樹這種東西……
最短路徑樹就是對於一個源點,到每一個點都有一個最短路徑,轉移到這個點的點設爲這個點的父親,然後我們就有了一顆以源點爲跟的樹。
這顆樹的每一條邊都是源點到其他點的最短路徑上的一條邊。
也就是說刪掉的邊如果不是最短路徑樹上的邊,那麼對這個點到所有點的距離都沒有影響。
那麼我們先處理出每一個點的最短路徑樹。
刪掉每一條邊之後,枚舉每一個點作爲源點,如果刪掉的這條邊不是最短路徑上的點,那就直接加上預處理出的答案,如果是,就重新跑一遍最短路。
只有當一條邊在最短路徑樹上時會重新計算,每棵最短路徑樹有n條邊,有n棵最小路徑樹,所以一共會重新計算n^2次。時間複雜度(n^2m)
代碼如下:
#include <cstdio>
#include <cstring>
#include <iostream>
#define N 120
#define M 12000
using namespace std;
int n,m,tmp;
int fa[N][N];
int fir[N],nes[M],v[M],tot=1;
int sum[N],dis[N];
bool pc[M],judge;
int dl[N],X[M],Y[M];
void edge(int x,int y)
{
v[++tot]=y;
nes[tot]=fir[x];
fir[x]=tot;
return;
}
#define edge(x,y) edge(x,y),edge(y,x)
int bfs(int S)
{
memset(dis,-1,sizeof(dis));
int l=1,r=1;
dis[S]=0; dl[1]=S;
fa[S][S]=0;
static int c;
int sum=0;
while(l<=r)
{
c=dl[l++];
sum+=dis[c];
for(int t=fir[c];t;t=nes[t])
{
if(~dis[v[t]] || pc[t]) continue;
dis[v[t]]=dis[c]+1;
fa[S][v[t]]=c;
dl[++r]=v[t];
}
}
return r==n?sum:-1;
}
void init()
{
tot=1;
judge=true;
memset(fir,0,sizeof(fir));
memset(sum,0,sizeof(sum));
for(int i=1;i<=m;i++)
{
scanf("%d%d",&X[i],&Y[i]);
edge(X[i],Y[i]);
}
for(int i=1;i<=n;i++)
if((sum[i]=bfs(i))==-1)
{
judge=false;
break;
}
}
int main()
{
while(scanf("%d%d",&n,&m)!=EOF)
{
init();
for(int i=1;i<=m;i++)
{
if(!judge) printf("INF\n");
else
{
int ans=0;
pc[i<<1]=true; pc[i<<1|1]=true;
for(int j=1;j<=n;j++)
{
if(fa[j][X[i]]!=Y[i] && fa[j][Y[i]]!=X[i]) ans+=sum[j];
else
{
if(~(tmp=bfs(j))) ans+=tmp;
else
{
ans=-1;
break;
}
}
}
if(~ans) printf("%d\n",ans);
else printf("INF\n");
pc[i<<1]=false; pc[i<<1|1]=false;
}
}
}
return 0;
}