話說割點概念,應該很好理解:
一個圖,如果一個點消失,這個點就不連通,那么這個點就是這個圖的割點(無向圖)
舉個例子:
很明顯,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); }
嗯,就關注