1. 程式人生 > >2018/2/11 每日一學 無向圖割頂和橋

2018/2/11 每日一學 無向圖割頂和橋

return set else 所有 scanf ear .net 存在 sin

割頂和橋:對於無向圖G,如果刪除某個節點u後,連通分量數目增加,則稱u為圖的割頂;如果刪除某條邊後,連通分量數目增加,則稱該邊為圖的橋。

對於連通圖刪除割頂或橋後都會使得圖不再連通。

我們利用dfs的性質來快速找出一個連通圖中的所有的割頂和橋。

設low[u]為u及其後代所能連回的最早的祖先的pre[]值,pre[]為時間戳則當u存在一個子節點v使得low[v] >= pre[u]時u就為割頂
同理當 low[v] > pre[u]時 u-v為橋

看代碼吧(轉自http://blog.csdn.net/stillxjy/article/details/70176689)

#include <iostream>
#include 
<cstdio> #include <algorithm> #include <cstring> #include <string> #include <cmath> #include <vector> using namespace std; const int maxn = 1000; int n,m; vector<int> G[maxn]; int low[maxn],pre[maxn]; int dfs_clock; //時間戳 int iscut[maxn]; //標記是否為割頂 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]) //沒有訪問的v { child++; //孩子節點的數目 int lowv = dfs(v,u); lowu = min(lowu,lowv); //用後代更新lowu if
(lowv >= pre[u]) iscut[u] = 1; if(lowv > pre[u]) cout<<"橋:"<<u<<"-"<<v<<endl; } else if(pre[v] < pre[u] && v != fa) //用反向邊更新lowu { lowu = min(lowu,pre[v]); } } if(fa < 0 && child == 1) iscut[u] = 0; //對於根節點的處理 low[u] = lowu; return lowu; } int main() { freopen("in.txt","r",stdin); while(scanf("%d%d",&n,&m)!=EOF) { memset(pre,0,sizeof(pre)); memset(iscut,0,sizeof(iscut)); for(int i=0;i<=n;i++) G[i].clear(); int u,v; for(int i=0;i<m;i++) { scanf("%d%d",&u,&v); G[u].push_back(v); G[v].push_back(u); } dfs(1,-1); for(int i=1;i<=n;i++) if(iscut[i]) cout<<i<<endl; } return 0; }

2018/2/11 每日一學 無向圖割頂和橋