圖的割點與割邊


話說割點概念,應該很好理解:

一個圖,如果一個點消失,這個點就不連通,那么這個點就是這個圖的割點(無向圖)

舉個例子:

很明顯,4就是這個圖的割點。

所以怎么求割點呢??

來來來,先上數據:

6 6
1 2
1 3
3 4
2 4
4 5
4 6

嗯,注意這是無向圖!!!

做法是這樣的

首先,記錄每一個點的時間截,也就是dfs第幾次搜索到這個點,時間截圖如下:

之后,記錄每個節點在不經過自己的節點范圍內,最小的時間截。

例如從3號點搜索到的4,那么4號點的最小時間截為1號點的1

再例如從4到達的5,那么5的最小時間截是4號點的3(注意可以到達4號點,只是不能經過)

最后,如果一個點的時間截>=它的下一個點的最小時間截,那么這個點就是割點。

舉個例子:4號點的下一個點有5和6和2,以5舉例,5的最小時間截是3,4的時間截是3,>=5號點最小時間及偶爾,所以4號點是割點。

代碼實現我們用到的是dfs,開始每個點的最小時間截,就是自己本身的時間截,然后在通過一條一條邊,不斷變少。

先呈上代碼,然后我們來模擬一下dfs過程:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cmath>
#include <cstring>
using namespace std;
int n,m;
int root;
int total=0;
int index=0;
int head[100010];
int book[100010];
int num[100010],low[100010];
struct edge
{
    int from;
    int to;
    int next;
}input[100010];
void add_edge(int a,int b)
{
    total++;
    input[total].from=a;
    input[total].to=b;
    input[total].next=head[a];
    head[a]=total;
}
void dfs(int now,int father)
{
    index++;
    int child=0;
    num[now]=index;
    low[now]=index;
    for(int e=head[now];e!=0;e=input[e].next)
    {
        if(num[input[e].to]==0)
        {
            child++;
            dfs(input[e].to,now);
            low[now]=min(low[now],low[input[e].to]);
            if(now!=root && low[input[e].to]>=num[now])
                book[now]=true;
            if(now==root && child==2)
                book[now]=true;
        }
        else if(input[e].to!=father)
            low[now]=min(low[now],num[input[e].to]);
    }
}
int main()
{
    cin>>n>>m;
    for(int i=1;i<=m;i++)
    {
        int a,b;
        cin>>a>>b;
        add_edge(a,b); 
        add_edge(b,a);
    }
    root=1;
    dfs(1,root); 
    for(int i=1;i<=n;i++)
        if(book[i])
            cout<<i<<" ";
}

開始還是一直遞歸,1——3——4——6

然后發現6無法遞歸,於是返回

到4,發現自己的最小時間截(以下簡稱low)比6的4要小,所以不改變。

然后到5,發現low還是比5的5要小,所以不改變。

接着到2,發現2的時間截還是更大,所以不改變。返回。

此時,2、5、6的low都比4的時間截大,所以4為截點

之后,發現從一號點每一個連着的點都被走過,所以循環終止

4為截點。

割點完畢。

然后割邊

一句話,割邊就刪一個等於號就好啦。

至於為什么很好想吧?

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cmath>
#include <cstring>
using namespace std;
int n,m;
int total=0;
int index=0;
int head[100010];
int num[100010],low[100010];
struct edge
{
    int from;
    int to;
    int next;
}input[100010];
void add_edge(int a,int b)
{
    total++;
    input[total].from=a;
    input[total].to=b;
    input[total].next=head[a];
    head[a]=total;
}
void dfs(int now,int father)
{
    index++;
    num[now]=index;
    low[now]=index;
    for(int e=head[now];e!=0;e=input[e].next)
    {
        if(num[input[e].to]==0)
        {
            dfs(input[e].to,now);
            low[now]=min(low[now],low[input[e].to]);
            if(low[input[e].to]>num[now])
                cout<<now<<"->"<<input[e].to<<endl;
                
        }
        else if(input[e].to!=father)
            low[now]=min(low[now],num[input[e].to]);
    }
}
int main()
{
    cin>>n>>m;
    for(int i=1;i<=m;i++)
    {
        int a,b;
        cin>>a>>b;
        add_edge(a,b); 
        add_edge(b,a);
    }
    dfs(1,1); 
}

嗯,就關注


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM