Centos系統目錄詳解
阿新 • • 發佈:2022-03-03
雙連通分量
定義
對於無向圖中兩點\(u,v\),若無論刪去哪條邊都不能使其不連通,則稱\(u,v\)邊雙連通
對於無向圖中兩點\(u,v\),若無論刪去哪個點都不能使其不連通,則稱\(u,v\)點雙連通
邊雙連通
我們發現使兩點不連通的邊其實就是橋(割邊)
所以我們只需要把橋刪了即可
void tarjan(int now,int fa) { dfn[now]=low[now]=++cnt; for (int i=beg[now];i;i=e[i].nex) { int nex=e[i].to; if (nex==fa) continue; if (!dfn[nex]) { tarjan(nex,now); chkmin(low[now],low[nex]); if (dfn[now]<low[nex]) e[i^1].cut=e[i].cut=1; } else chkmin(low[now],dfn[nex]); } } void dfs(int now,int fa,int C) { col[C].push_back(now); bel[now]=C; for (int i=beg[now];i;i=e[i].nex) { int nex=e[i].to; if (nex==fa || bel[nex] || e[i].cut) continue; dfs(nex,now,C); } }
點雙連通
我們發現,兩個點雙一定有一個割點連線,且這個割點被兩個點雙包含,所以我們可以直接根據強連通分量的方式,把點入棧,然後找到割點就不停彈出點,並全部存入點雙
void tarjan(int now,int Fa) { dfn[now]=low[now]=++cnt;st[++top]=now; if (now==Fa && !beg[now]) col[++tot].push_back(now); for (int i=beg[now];i;i=e[i].nex) { int nex=e[i].to; if (nex==Fa) continue; if (!dfn[nex]) { tarjan(nex,now); chkmin(low[now],low[nex]); if (dfn[now]<=low[now]) { ++tot; while(1) { col[++tot].push_back(st[top]); if (st[top]==nex) {top--;break;} top--; } col[tot].push_back(now); } } else chkmin(low[now],dfn[nex]); } }
圓方樹
圓方樹主要用於處理仙人掌圖(每條邊在不超過一個簡單環中的無向圖)的問題
在剛剛的點雙基礎上,我們來構建一棵圓方樹
我們將原來的點看做一個圓點,對於一個點雙建一個方點,方點向該點雙裡的每個圓點連邊
那麼,每個點雙就是一個菊花,然後整張圖是由割點連線很多菊花
當原圖是一個聯通圖時,我們構建的圖就是一棵樹
然後,我們考慮如何實現這個構建過程
由於圓方樹基於點雙,所以在求點雙的過程中可以建出這棵樹
void tarjan(int now,int fa) { dfn[now]=low[now]=fa; if (now==fa && !beg[now]) { cntcol++; E[cntcol].push_back(now); E[now].push_back(cntcol); } st[++top]=now; for (int i=beg[now];i;i=e[i].nex) { int nex=e[i].to; if (nex==fa) continue; if (!dfn[nex]) { tarjan(nex,now); chkmin(low[now],low[nex]); if (low[nex]<=dfn[now]) { cntcol++; while(1) { E[cntcol].push_back(st[top]); E[st[top]].push_back(cntcol); if (st[top]==nex) {top--;break;} top--; } E[cntcol].push_back(now); E[now].push_back(cntcol); } else chkmin(low[now],dfn[nex]); } } }