最近做到了割邊割點的東西。就把這幾天學到的寫下來。
在一個無向圖中。
割點:就是刪除了這個點,圖會不在連通或者連通分量增加。
割邊:刪除一條邊,圖會不在連通或者連通分量增加。
做割點時候,會用到兩個數組。low[],dfn[]、
low[]數組保存的可以回到祖先的最小節點。
dfn[]數組保存的是當前節點的序列號,可能和題目給出的序列號不是一個數字,要看走的順序。
然後又由於刪除一個點後,當這個點是割點之後,那麼這個點的子節點就不會返回到之前的祖先。
當U指向V
low[now]=min(low[now],dfn[v]);當遇到返祖邊的時候
low[now]=min(low[now],low[v]);
割點的判斷if(child>1&&now==1||now!=1&&low[v]>=dfn[now])
當他的low[]的子節點大於等於他的話。則說明這個點是他的祖先。
假如這個點不是起點的話, 一定是這個圖的割點。將這個分割開的點。
假如是起點話,需要兩個以上的子樹。
以hiho一下 第五十二週 的題目爲例。點擊打開鏈接
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int maxn=1000001;
const int INF=1<<29;
int n,m,sum;
int e,cnt[maxn],kk=0;;
int head[maxn],nxt[maxn],pnt[maxn];
int low[maxn],dfn[maxn],vis[maxn];
//low[]數組保存的可以回到祖先的最小節點。
//dfn[]數組保存的是當前節點的序列號,可能和題目給出的序列號不是一個數字,要看走的順序。
int aa[maxn],ck=0;
struct node
{
int x,y;
}num[maxn];
int cmp(node p1,node p2)
{
if(p1.x==p2.x) return p1.y<p2.y;
return p1.x<p2.x;
}
void AddEdge(int u,int v)
{
pnt[e]=v;nxt[e]=head[u];head[u]=e++;
}
void dfs(int now,int father,int dfnth)
{
low[now]=dfn[now]=dfnth;
vis[now]=1;
int child=0;
//printf("==%d %d %d\n",now,father,dfnth);
for(int i=head[now];i!=-1;i=nxt[i])
{
if(pnt[i]!=father&&vis[pnt[i]]==1){//遇到返祖邊的時候,就更新low[]值
// printf("!!%d %d %d %d\n",now,pnt[i],father,dfn[pnt[i]]);
low[now]=min(low[now],dfn[pnt[i]]);
}
if(!vis[pnt[i]])
{
dfs(pnt[i],now,dfnth+1);
child++;
low[now]=min(low[now],low[pnt[i]]);
if(low[pnt[i]]>dfn[now])//割邊
{
num[kk].x=min(now,pnt[i]);
num[kk++].y=max(now,pnt[i]);
}
if(child>1&&now==1||now!=1&&low[pnt[i]]>=dfn[now])//割點,
{
cnt[now]=1;
sum++;
}
}
}
vis[now]=2;
}
int main()
{
scanf("%d%d",&n,&m);
e=0;
sum=0;
memset(head,-1,sizeof(head));
memset(dfn,0,sizeof(dfn));
memset(vis,0,sizeof(vis));
memset(cnt,0,sizeof(cnt));
int u,v;
for(int i=0;i<m;i++)
{
scanf("%d%d",&u,&v);
AddEdge(u,v);
AddEdge(v,u);
}
if(n==2)
{
puts("NULL");
puts("1 2");
return 0;
}
dfs(1,-1,1);
for(int i=1;i<=n;i++)
printf("%d ",low[i]);puts("");
for(int i=1;i<=n;i++)
printf("%d ",dfn[i]);puts("");
if(sum!=0)
{
for(int i=1; i<=n; i++)
if(cnt[i])aa[ck++]=i;
for(int i=0; i<ck; i++)
printf("%d%c",aa[i],i==ck-1?'\n':' ');
}
else
puts("Null");
if(kk!=0)
{
sort(num,num+kk,cmp);
printf("%d %d\n",num[0].x,num[0].y);
for(int i=1; i<kk; i++)
if(num[i-1].x!=num[i].x||num[i-1].y!=num[i].y)
printf("%d %d\n",num[i].x,num[i].y);
}
return 0;
}
/*
6 7
1 2
2 3
3 1
2 4
4 5
5 6
6 4
8 12
1 2
2 3
2 1
2 4
3 2
3 4
4 2
4 3
4 5
5 4
8 7
7 8
6 8
2 5
1 2
2 3
3 1
3 4
4 5
5 6
6 4
7 7
1 2
2 3
3 4
2 5
4 5
5 6
5 7
*/