【CodeForces - 1000E :We Need More Bosses】無向圖縮點+樹的直徑

https://www.cnblogs.com/hua-dong/p/9238757.html
觀摩了大佬的代碼,並添加了詳細的註釋。
用兒子等不等於自己的爸爸判斷是不是計算了反向邊!

#include<bits/stdc++.h>
#define ll long long 
using namespace std;
const int maxn=600010;
int From[maxn],//邊的起點 
Laxt[maxn],// 以u爲起點的一條邊的儲存位置 
To[maxn<<2],//邊的終點 
Next[maxn<<2],//同起點的下一條邊 
cnt;//邊的數量(雙向) 
int low[maxn], //tarjan輔助數組 
dfn[maxn], //tarjan輔助數組 
times, //tarjan輔助 
q[maxn],  //tarjan輔助棧 
head, //棧頂 
scc_cnt, //顏色種類 
scc[maxn]; //顏色 
vector<int>G[maxn]; //縮點之後的圖 
int dis[maxn],S,T,ans;
void add(int u,int v)
{
    Next[++cnt]=Laxt[u];
	From[cnt]=u;
    Laxt[u]=cnt; To[cnt]=v;
}
void tarjan(int u,int fa)
{
    dfn[u]=low[u]=++times; 
    q[++head]=u;
    for(int i=Laxt[u];i;i=Next[i]){
        if(To[i]==fa) continue;
        if(!dfn[To[i]]) {
              tarjan(To[i],u);
              low[u]=min(low[u],low[To[i]]);
        }
        else low[u]=min(low[u],dfn[To[i]]);
    }
    if(low[u]==dfn[u]){
        scc_cnt++;
        while(true){
            int x=q[head--];
            scc[x]=scc_cnt;
            if(x==u) break;
        }
    }
}
void dfs(int u,int f)
{
    dis[u]=dis[f]+1;
    for(int i=0;i<G[u].size();i++){
        if(G[u][i]!=f) dfs(G[u][i],u);
    }
}
int main()
{
    int N,M,u,v,i,j;
    scanf("%d%d",&N,&M);
    for(i=1;i<=M;i++){
        scanf("%d%d",&u,&v);
        add(u,v); add(v,u);
    }
    tarjan(1,0);//保證圖是聯通的,所以纔會只需要搜一個,否則需要遍歷1~n 
    for(i=1;i<=N;i++){
        for(j=Laxt[i];j;j=Next[j]){
           if(scc[i]!=scc[To[j]]) //如果兒子顏色和爸爸不一樣 
             G[scc[i]].push_back(scc[To[j]]);//就加入爸爸到兒子的路 
        }
    }//醬紫,應該會獲得一個有雙向邊的樹 
    //開始求樹的直徑 
    dfs(1,0);//從任一點出發,找到最遠的 (必然是一個葉子 
    for(i=1;i<=scc_cnt;i++) if(dis[i]>dis[S]) S=i;  
    dfs(S,0);//從最遠點出發,找到離它最遠的 (必然是另一個葉子 
    for(i=1;i<=scc_cnt;i++) ans=max(ans,dis[i]-1);
    printf("%d\n",ans);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章