強聯通分量tarjan
一.模板介紹
1.定義
給定一張有向圖,若存在一個點集,該點集內的點可通過路徑任意到達其他所有點,則稱該點集為一個強聯通分量。(一個點也可為一個強聯通分量)
2.演算法tarjan
結果:將強聯通分量縮成一個點,讓一個有環圖變成一張無環圖
#include<bits/stdc++.h>
using namespace std;
const int N=20005;
const int M=1e5+5;
struct ppp {
int u,v,next;
} e[2*M];
int vex[N],k;
int dfn[N],low[N],cnt;
int stk[N],top,color[N],co,ans[N],instk[N];
int n,m;
//dfn為次序,low為該點所能遍歷的次序最早的點
void add(int u,int v) {
k++;
e[k].u=u;
e[k].v=v;
e[k].next=vex[u];
vex[u]=k;
return;
}
void tarjan(int u) {
dfn[u]=low[u]=++cnt;
instk[u]=1;
stk[++top]=u;//用棧儲存強連通,u點入棧
for(int i=vex[u]; i; i=e[i].next) {
int v=e[i].v;
if(!dfn[v]) {
tarjan(v,root);
low[u]=min(low[v],low[u]);
//如果v能遍歷到的點比u能遍歷到的最小點小,就改值
}
else if(instk[v])low[u]=min(low[u],dfn[v]);
//如果v的次序比u的遍歷到的最小點小,就改值
}
if(dfn[u]==low[u]){//則該點為強連通的最早點
co++;
while(1){
int t=stk[top];//從棧頂到這個點的所有點,都是該強聯通分量的點集
color[t]=co;//屬於一個強聯通分量的點顏色相同
top--;
instk[t]=0;//出棧
if(t==u)break;
}
}
}
void solve(){
co=n; //如果需要對縮完後的點建圖,則co要從n+1開始
for(int i=1; i<=n; i++) {
if(!dfn[i])tarjan(i,i);
}
for(int u=1;u<=n;u++){
for(int i=vex[u];i;i=e[i].next){
int v=e[i].v;
if(color[u]!=color[v])add(color[u],color[v]);
//後來是以縮點後的強聯通分量顏色來建無向圖
}
}
}
int main() {
int u,v;
cin>>n>>m;
for(int i=1; i<=m; i++) {
cin>>u>>v;
add(u,v);
add(v,u);
}
solve();
return 0;
}
3.開始刷題
只需要在tarjan完之後,求入度為0的點的數量即可
void xxks(){
int ans=0;
for(int u=1;u<=n;u++){
for(int i=vex[u];i;i=e[i].next){
int v=e[i].v;
if(color[u]!=color[v])in[color[v]]++;
//求入度為0的點為擴散源
}
}
for(int i=1;i<=co;i++){
if(in[i]==0)ans++;
}
cout<<ans;
}
二.割點
1.定義
給定一張無向連通圖,若存在點u滿足刪除該點後,連通圖不再連通,則該點u為該圖的割點
2.演算法tarjan
過程
tarjan跑一個深搜優先樹
對於根節點:若其有兩個以上的孩子,則該點為割點
對於非根點:若從u出發跑,不能到達u的上層,則u點為割點
根據定義很好寫出程式碼
void tarjan(int u,int root) {
dfn[u]=low[u]=++cnt;
instk[u]=1;
stk[++top]=u;
int child=0;
for(int i=vex[u]; i; i=e[i].next) {
int v=e[i].v;
if(!dfn[v]) {
tarjan(v,root);
low[u]=min(low[v],low[u]);
if(low[v]>=dfn[u]&&u!=root)cut[u]=1;
//由子節點出發能到的最早點在該節點後面或等於該節點則為割點
//不為if(low[u]>=dfn[u])的原因:只要由一個子節點滿足情況則u就為割點
if(u==root)child++;//統計根節點的孩子數
}
low[u]=min(low[u],dfn[v]);
}
if(u==root&&child>=2)cut[u]=1;//根節點有兩個子樹則為割點
if(dfn[u]==low[u]){
co++;
while(1){
int t=stk[top];
color[t]=co;
top--;
instk[t]=0;
if(t==u)break;
}
}
}
相關文章
- Tarjan求強連通分量
- 【模板】tarjan 強連通分量縮點
- 強連通分量(Tarjan演算法)演算法
- Tarjan演算法(強連通分量分解)演算法
- Tarjan 求有向圖的強連通分量
- 圖論——強連通分量(Tarjan演算法)圖論演算法
- kosaraju 和 tarjan演算法詳解(強連通分量)演算法
- 尋找圖的強連通分量:tarjan演算法簡單理解演算法
- 強聯通分量及縮點法
- 20行程式碼實現,使用Tarjan演算法求解強連通分量行程演算法
- 強連通------tarjan演算法詳解及與縮點聯合運用演算法
- 【Tarjan SCC 加邊使得所有圖聯通 至少選取多少個點能圖聯通 】Network of Schools加強版.md
- 強連通分量
- UVA1327 && POJ1904 King's Quest(tarjan+巧妙建圖+強連通分量+縮點)
- POJ 1236 Network of Schools 強連通分量
- 有向圖的強連通分量 模版
- 連通圖與Tarjan演算法演算法
- 【演算法學習】tarjan 強連通、點雙、邊雙及其縮點 重磅來襲!!!!演算法
- 無向連通圖點雙連通分量
- 無向連通圖邊雙連通分量
- Tarjan
- UVA-11504 - Dominos(有向圖的強連通分量)
- Day7 割點、割邊和強連通分量
- tarjan[模板]
- 圖論系列之「深度優先遍歷及聯通分量」圖論
- 直流分量2
- 強連通分量及縮點 演算法解析及例題演算法
- tarjan2
- 邊分治維護強連通分量(CF1989F,P5163)
- 連通圖演算法詳解之① :Tarjan 和 Kosaraju 演算法演算法
- Tarjan再學習
- LCA(倍增與Tarjan)
- Zotero Translate 聯動 DeepL翻譯 強強聯手
- Tarjan 學習筆記筆記
- tarjan學習筆記筆記
- HDU 2586 倍增 / Tarjan LCA
- bzoj2427: [HAOI2010]軟體安裝(強聯通+樹形Dp)
- OKR與Scrum如何強強聯手OKRScrum