连通图/割点、割边
先了解一下每個名詞的含義
無向圖:沒有方向的圖
無向連通圖:圖中任意兩節點可互相到達的無向圖
無向非連通圖:不是無向連通圖
無相連通分量:無向非連通圖中的最大連通子圖
割點:刪掉這個點就不連通
割邊:刪掉這個邊就不連通
強聯通有向圖:任意兩點可以到達的有向圖
弱連通有向圖:如果忽略邊的方向是一個無向連通圖
強聯通分量(SCC):非強連通圖的極大連通子圖
對于求無向圖中的割點和割邊
為什么有割點和非割點之分,那就是由于無向圖連通有環,環中的點自然不是割點,如果無向連通圖要是樹的話,那么所有點就都是割點了
對于Tarjan算法,則是選擇一個為根節點進行dfs搜索,用dfn數組存儲每個節點出現時間(時間從1開始,0代表沒搜過)
如果該圖中有環那么該環中一定有first(最早出現的節點)和last(最晚出現的節點),而且last與fisrt有邊能直接相連,當last搜尋下一個節點時便會搜到first
這時需要一個low數組存儲每個點能搜索到的最早出現的時間,只有對于環中last搜到fisrt時,low數組能變小,而且會讓從fisrt->last這條樹鏈上的所有點i,使得low[i]=min(low[i],dfn[first])(代碼中應該是low[u]=min(low[u],low[v]))
搜完所有點以后
若求割點每個點可以分為根節點和不是根節點
對于根節點,若有兩個子節點那么該點即是割點(對于如何判斷有幾個子節點,在搜索時用一個fa[]數組存好由誰轉移過來的,最后以判斷有幾個是由根節點轉換的即可)
對于不是根節點i,若low[i]>=dfn[fa[i]]則該點父親是割點(因為該點不通過該點與父親的邊最多只能搜到父親節,那么刪掉父親節點,該點則不能搜到父親以上節點)
若求割邊,只需要搜每個不是根節點的點i,若low[i]>dfn[fa[i]]那么該點與父親連的邊為割邊(因為若該點所能搜到的最早出現的點也比父親出現的晚,說明該點不能搜到父親上面的點)
代碼如下
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<vector>
using namespace std;
int dfn[1005],low[1005],fa[1005];
bool vis[1005];
vector<int>G[1005];
int cnt;
void tarjan(int u)
{
dfn[u]=low[u]=++cnt;
int i,j;
for(i=0; i<G[u].size(); i++)
{
int v=G[u][i];
if(dfn[v]==0)
{
fa[v]=u;
tarjan(v);
low[u]=min(low[u],low[v]);
}
else
low[u]=min(low[u],dfn[v]);
}
}
int gedian(int n)
{
int num=0;
memset(vis,false,sizeof(vis));
int i,j,fu;
for(i=2; i<=n; i++)
{
fu=fa[i];
if(fu==1)
num++;
else
{
if(low[i]>=dfn[fu])
vis[fu]=true;
}
}
if(num>=2)
vis[1]=true;
int sum=0;
for(i=1; i<=n; i++)
{
if(vis[i])
sum++;
}
return sum;
}
int gebian(int n)
{
int i,j,sum=0,fu;
for(i=1;i<=n;i++)
{
fu=fa[i];
if(fu>0&&low[i]>dfn[fu])
sum++;
}
return sum;
}
int main()
{
int n,m;
while(scanf("%d %d",&n,&m)!=EOF)
{
int i,j;
for(i=1; i<=n; i++)
G[i].clear();
int x,y;
for(i=0; i<m; i++)
{
scanf("%d %d",&x,&y);
G[x].push_back(y);
G[y].push_back(x);
}
memset(dfn,0,sizeof(dfn));
cnt=0;
memset(fa,0,sizeof(fa));
tarjan(1);
}
}
跑一遍taijan以后有向圖變成一棵樹,對于原圖環中一定被舍掉,但恰恰由于這條邊改變了low值,因為樹都是從上指向下,只有這條邊往上指了,使得
該邊下邊點low值可以變成上邊點dfn值
求割點
對于根如果有兩棵子樹則該點是割點
否則若該點u存在一個子節點v使得 low[v]>=dfn[u]則u為割點
求割邊
對于某條邊的子節點v父節點u存在 low[v]>dfn[u]則該邊為割邊
總結
- 上一篇: 数据库容量和内存测算的一些想法
- 下一篇: bat获取外部参数值