Luogu P3388 割點模板

2022-06-06 07:45:11 字數 1725 閱讀 9183

luogu p3388

在乙個無向圖中,如果有乙個頂點集合,刪除這個頂點集合以及這個集合中所有頂點相關聯的邊以後,圖的連通分量增多,就稱這個點集為割點集合。

如果某個割點集合只含有乙個頂點x(也即是乙個割點集合),那麼x稱為乙個割點。

為了便於理解,我們可以從狹義上進行分析:對於乙個連通無向圖,刪去其中的乙個點可以令這個圖不再連通,那麼這個點就是割點(之一)。

那麼再推廣一下:對於乙個無向圖,刪除其中乙個點,使這個圖的連通塊增多,那麼這個點就是割點之一。

對於這一類題目,仍然可以採用類似求強連通分量時使用的tarjan演算法進行求解。

【luogu p3387】縮點模板(強連通分量tarjan&拓撲排序)

如果沒有學習過相關知識,可以看這一篇部落格。

做法如下:

先考慮對於當前搜尋樹的根節點,很容易想到如果它有多棵子樹(其實這麼說不太對,可以說是根節點有多個直接子節點),那麼這個根節點肯定就會是乙個割點。

那麼對於非根節點呢?像是求強連通分量時的做法一樣,尋找返祖邊。用low陣列記錄每個點能返回的最早訪問的節點。

想象下面這樣一種情況:如果low[v]>=dfn[u],說明v節點及其以下的任何乙個節點都不可能不經過u節點訪問到u節點以前的節點,在這樣的情況下,u節點就成為了乙個割點。

還有乙個通常爭議較大的地方,比較難以理解:

假設當前節點走到了一條往回走的邊

low[now]=min(low[now],dfn[v]);//now即上文提到的u

在更新low的時候,這一句不能夠寫成下面的形式

low[now]=min(low[now],low[v]);

原因如下:我們知道low[v]記錄是v能通過非樹邊(通常是返祖邊,橫叉邊有的時候也是可以的)訪問到的最早的節點,那麼low[v]記錄的節點必然在v之前或剛好為v。假設這樣一種情況,low[v]記錄的節點在v之前,那麼按照第二種更新方法,low[now]被更新成v以前的節點。當我們回溯到節點v進行判斷時,我們不會將v節點判定為割點,因為他的子節點now能訪問到v以前的節點,不符合low[v]>=dfn[u]的條件。事實上,這種情況下,v也是乙個割點。

可以自行畫圖進行理解

**如下:

#include#includeusing namespace std;

const int maxn=2*1e4+15,maxm=1e5+10;

struct data

e[2*maxm];

int dfn[maxn],low[maxn],tim,head[maxn],n,m,x,y,ans;

bool cut[maxn];

void tarjan(int now,int root)

low[now]=min(low[now],dfn[v]);

} if (now==root&&bt>1) cut[root]=true;

}int main()

for (int i=1;i<=n;i++) if (!dfn[i]) tarjan(i,i);

for (int i=1;i<=n;i++) if (cut[i]) ans++;

printf("%d\n",ans);

for (int i=1;i<=n;i++) if (cut[i]) printf("%d ",i);

return 0;

}

Luogu P3388 模板 割點(割頂)

割點 給出乙個nn個點,mm條邊的無向圖,求圖的割點。輸入格式 第一行輸入n,mn,m 下面mm行每行輸入x,yx,y表示xx到yy有一條邊 輸出格式 第一行輸出割點個數 第二行按照節點編號從小到大輸出節點,用空格隔開 輸入樣例 1 複製 6 7 1 21 3 1 42 5 3 54 5 5 6輸出...

Luogu P3388 模板 割點(割頂)

一道求割點的板子題。還是採用經典的tarjan演算法。首先大致和tarjan求強連通分量相似,都是用 dfn x 表示訪問到 x 的時間 時間戳 low x 表示通過 x 回邊能走到的時間戳最小的點的時間戳。然後我們考慮一下對於乙個點如何判斷它是否為割點 low now min low now df...

割點 (模板) 洛谷3388

題目背景 割點題目描述 給出乙個n個點,m條邊的無向圖,求圖的割點。輸入輸出格式 輸入格式 第一行輸入n,m 下面m行每行輸入x,y表示x到y有一條邊 輸出格式 第一行輸出割點個數 第二行按照節點編號從小到大輸出節點,用空格隔開 輸入輸出樣例 輸入樣例 1 複製 6 7 1 2 1 3 1 4 2 ...