無向圖割頂與橋
阿新 • • 發佈:2018-11-09
#include<cstdio> #include<cstring> #include<vector> using namespace std; const int maxn=100000+10; int n,m; int dfs_clock;//時鐘,每訪問一個節點增1 vector<int> G[maxn];//G[i]表示i節點鄰接的所有節點 int pre[maxn];//pre[i]表示i節點被第一次訪問到的時間戳,若pre[i]==0表示i還未被訪問 int low[maxn];//low[i]表示i節點及其後代能通過反向邊連回的最早的祖先的pre值 bool iscut[maxn];//標記i節點是不是一個割點 //求出以u為根節點(u在DFS樹中的父節點是fa)的樹的所有割頂和橋 //初始呼叫為dfs(root,-1); int dfs(int u,int fa) { int lowu=pre[u]=++dfs_clock; int child=0; //子節點數目 for(int i=0; i<G[u].size(); i++) { int v=G[u][i]; if(!pre[v]) { child++;//未訪問過的節點才能算是u的孩子 int lowv=dfs(v,u); lowu=min(lowu,lowv); if(lowv>=pre[u])//因為若這樣刪除u後v及v的子樹不可到達u的祖先; { iscut[u]=true; //u點是割頂 if(lowv>pre[u]) //(u,v)邊是橋,v想要到達u必須經過u,v這條邊,刪除後不連通; printf("邊(%d, %d)是橋\n",u,v); } } else if(pre[v]<pre[u] && v!=fa)//v!=fa確保了(u,v)是從u到v的反向邊 { lowu=min(lowu,pre[v]);//v已經訪問過, } } if(fa<0 && child==1 ) iscut[u]=false;//u若是根且孩子數<=1,那u就不是割頂 return low[u]=lowu; } int main() { while(scanf("%d%d",&n,&m)==2&&n) { dfs_clock=0;//初始化時鐘 memset(pre,0,sizeof(pre)); memset(iscut,0,sizeof(iscut)); for(int i=0;i<n;i++) G[i].clear(); for(int i=0;i<m;i++) { int u,v; scanf("%d%d",&u,&v); G[u].push_back(v); G[v].push_back(u); } dfs(1,-1);//初始呼叫 for(int i=0;i<n;i++)if(iscut[i]==true) printf("割頂是:%d\n",i); } return 0; }