割顶和桥:对于无向图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; }