hiho一下 第五十二週(割邊 割點)

最近做到了割邊割點的東西。就把這幾天學到的寫下來。

在一個無向圖中。

割點:就是刪除了這個點,圖會不在連通或者連通分量增加。

割邊:刪除一條邊,圖會不在連通或者連通分量增加。


做割點時候,會用到兩個數組。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
*/



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章