HDU2433 Travel 最短路徑樹

題目大意:
有一個n(n<=100 )個點m(m<=3000 )條邊的無向圖,邊權爲1,求刪掉每一條邊之後,每個點到所有點的最短距離和。
多組數據

題目分析:
最暴力的方法就是刪掉每一條邊,然後枚舉每一個點,跑一邊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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章