找割点和割边
#include <iostream> #include <cstdio> using namespace std; int n,m,e[9][9],root; int num[9],low[9],flag[9],index; void dfs(int cur,int father){ int child= 0,i; index++; num[cur]=index; low[cur]=index; for(i=1;i<=n;i++){//枚举与当前顶点cur有边相连的顶点i if(e[cur][i]==1) { if(num[i]==0)//如果顶点i的时间戳为0,说明顶点还没有被访问过 { //从生成树的角度来说,此时的i为cur的儿子 child++; dfs(i,cur);//继续往下深度优先遍历 //更新当前顶点cur能访问到最早顶点的时间戳 low[cur]=min(low[cur],low[i]); //如果当前顶点不是根节点并且满足low[i]>=num[cur],则当前顶点为割点 if(cur!=root&&low[i]>=num[cur]) flag[cur]=1; //如果当前顶点是根节点,在生成树中根节点必须有两个儿子,那么这个根节点才是割点 if(cur==root&&child==2) flag[cur]=1; } else if(i!=father)//否则如果顶点i曾经被访问过,并且这个顶点不是当前顶点cur的父亲 //则说明此时的i为cur的祖先,因此需要更新当前节点cur能访问到最早顶点的时间戳 { low[cur]=min(low[cur],num[i]); } } } return ; } int main() { //freopen("in.txt","r",stdin); int i,j,x,y; cin>>n>>m; for(i=1;i<=n;i++) for(j=1;j<=n;j++) e[i][j]=0; for(i=1;i<=m;i++){ cin>>x>>y; e[x][y]=1; e[y][x]=1; } root = 1; dfs(1,root);//从1号顶点开始深度优先搜索 for(i=1;i<=n;i++){ if(flag[i]==1) printf("%d ",i); } return 0; }
找割边的话,只需要吧child删掉,把low>=num[u]改为low[v]>num[u],取消一个等号即可,有等号的话代表点v是不可能在不经过父亲节点u而回到祖先(包括父亲)的,所以顶点u是割点。相等表示还可以回到父亲,而没有等号的表示连父亲都回不到了。倘若顶点v不能回到祖先,也没有另一条路回到父亲,那么v-u这条边就是割边。
代码:
#include <iostream> #include <iostream> #include <cstdio> using namespace std; int n,m,e[9][9],root; int num[9],low[9],flag[9],index; void dfs(int cur,int father){ int i; index++; num[cur]=index; low[cur]=index; for(i=1;i<=n;i++){//枚举与当前顶点cur有边相连的顶点i if(e[cur][i]==1) { if(num[i]==0)//如果顶点i的时间戳为0,说明顶点还没有被访问过 { //从生成树的角度来说,此时的i为cur的儿子 dfs(i,cur);//继续往下深度优先遍历 //更新当前顶点cur能访问到最早顶点的时间戳 low[cur]=min(low[cur],low[i]); //如果当前顶点不是根节点并且满足low[i]>num[cur],则当前顶点为割点 if(low[i]>num[cur]) printf("%d-%d\n",cur,i); } else if(i!=father)//否则如果顶点i曾经被访问过,并且这个顶点不是当前顶点cur的父亲 { low[cur]=min(low[cur],num[i]); } } } return ; } int main() { freopen("in.txt","r",stdin); int i,j,x,y; cin>>n>>m; for(i=1;i<=n;i++) for(j=1;j<=n;j++) e[i][j]=0; for(i=1;i<=m;i++){ cin>>x>>y; e[x][y]=1; e[y][x]=1; } root = 1; dfs(1,root);//从1号顶点开始深度优先搜索 return 0; }