图论:求割点(无向图中的概念)
回边:dfs过程中遇到已访问节点所经过的边观察dfs树,有两类节点可成为割点。
对非叶子节点u,若子树节点均无指向u的祖先节点的回边,说明删除u后,根节点与u的子树不在连通,则u为割点。
dfsn[u]记录u节点的dfs序号。
low[u]记录节点u或u的子树能追溯到的最早祖先
当(u,v)为树边,且low[to]>=dfsn[from],节点from为割点。
对于上图,割点为2跟3。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXN=10;
int* node;
int dfsn[MAXN],low[MAXN],c=0;
bool vis[MAXN];
struct edge{
int to,next;
edge(){}
edge(int v,int w):to(v),next(w){}
};
edge e[MAXN*2];
void tarjan(int from){
static int cnt=0;
vis[from]=true;
dfsn[from]=low[from]=cnt++;
for(int i=node[from];i+1;i=e[i].next){
int to=e[i].to;
if(!vis[to]){
tarjan(to);
low[from]=min(low[from],low[to]);
if(from!=0&&low[to]>=dfsn[from]){
printf("%d ",from);
}
}else{
low[from]=min(low[from],dfsn[to]);
}
}
}
void addEdge(int from,int to){
e[c].to=to;
e[c].next=node[from];
node[from]=c++;
}
int main(){
freopen("./in.txt","r",stdin);
node=new int[MAXN];
int n,u,v;
memset(node,-1,MAXN*sizeof(int));
memset(vis,false,sizeof(vis));
scanf("%d",&n);
for(int i=0;i<n;i++){
scanf("%d%d",&u,&v);
addEdge(u,v);
addEdge(v,u);
}
tarjan(0);
return 0;
}
如何判断根节点是割点呢?dfs一个方向的话会访问所有的点,如果存在根节点访问了两个子节点,那么就说明有两个区域,也就是生成树上有两个子树
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXN=10;
int* node;
int dfsn[MAXN],low[MAXN],c=0;
bool vis[MAXN];
struct edge{
int to,next;
edge(){}
edge(int v,int w):to(v),next(w){}
};
edge e[MAXN*2];
void tarjan(int from){
static int cnt=0;
int child=0;
vis[from]=true;
dfsn[from]=low[from]=cnt++;
for(int i=node[from];i+1;i=e[i].next){
int to=e[i].to;
if(!vis[to]){
child++;
tarjan(to);
low[from]=min(low[from],low[to]);
if(from!=3&&low[to]>=dfsn[from]){
printf("%d ",from);
}
}else{
low[from]=min(low[from],dfsn[to]);
}
}
if(child>=2){
printf("%d\n",from);
}
}
void addEdge(int from,int to){
e[c].to=to;
e[c].next=node[from];
node[from]=c++;
}
int main(){
freopen("./in.txt","r",stdin);
node=new int[MAXN];
int n,u,v;
memset(node,-1,MAXN*sizeof(int));
memset(vis,false,sizeof(vis));
scanf("%d",&n);
for(int i=0;i<n;i++){
scanf("%d%d",&u,&v);
addEdge(u,v);
addEdge(v,u);
}
tarjan(3);
return 0;
}
in.txt
8
0 1
1 2
2 3
0 3
3 4
3 5
4 5
2 6