Tarjan演算法 縮點染色及最小權點基

2021-09-25 23:21:35 字數 2409 閱讀 6861

看了許多部落格,還是這個最清楚:強連通演算法–tarjan個人理解+詳解

牆裂安利大家看看上面的部落格!講的非常清楚!(但是文章的**好像有一點點小錯誤。

tarjan演算法主要解決了有向圖中有幾個強連通分量的問題,基於tarjan演算法,可以對在同一連通分量的點染色,進而縮點,生成有向無環圖。

例:給定有向圖,求:

至少要選幾個頂點,才能做到從這些頂點出發,可以到達全部頂點

至少要加多少條邊,才能使得從任何乙個頂點出發,都能到達全部頂點

思路縮點之後, dag上面有多少個入度為0的頂點,問題1的答案就是多少;在dag上要加幾條邊,才能使得dag變成強連通的,問題2的答案就是多少。

加邊的方法:

假定有 n 個入度為0的點,m個出度為0的點,如何加邊?

把所有入度為0的點編號 0,1,2,3,4 …n -1

每次為乙個編號為i的入度0點可達的出度0點,新增一條出邊,連到編號為(i+1)%n 的那個入度0點,這需要加n條邊。

若 m <= n,則加了這n條邊後,已經沒有入度0點,則問題解決,一共加了n條邊

若 m > n,則還有m-n個入度0點,則從這些點以外任取一點,和這些點都連上邊,即可,這還需加m-n條邊。

所以,max(m,n)就是第二個問題的解

附上**:

#include

//**僅供參考

#include

#include

#include

#include

using namespace std;

#define maxn 1000000

struct eedge[maxn]

;int head[maxn]

,k;int vis[maxn]

;int dfn[maxn]

,low[maxn]

,cnt,sig,color[maxn]

;int in_cnt,out_cnt,in[maxn]

,out[maxn]

;int n,m;

stack<

int>s;

void

init()

void

add(

int u,

int v)

void

tarjan

(int u)

else

if(vis[v]==1

)}if(dfn[u]

== low[u]

)while(1

);printf

("\n");

}}void

slove()

printf

("強連通分量共%d個\n"

,sig);}

//1) 至少要選幾個頂點,才能做到從這些頂點出發,可以到達全部頂點

//2) 至少要加多少條邊,才能使得從任何乙個頂點出發,都能到達全部頂點

void

scc(

)else}}

for(

int i =

1; i <= sig;

++i)

printf

("至少要選 %d 個頂點,才能從這些頂點出發,可達全部頂點\n至少要加 %d 條邊,使得從任何乙個頂點出發,到達全部頂點\n"

,in_cnt,

max(in_cnt,out_cnt));

}}intmain()

slove()

;for

(int i =

1; i <= n;

++i)

scc();

}}

一組測試用例

強連通圖縮點的應用:最小點基

題目大意:

給你n個炸彈,對應已知其座標和**範圍,以及引爆這個炸彈需要的花費,對應如果引爆了炸彈a,沒有引**彈b,但是b炸彈在a炸彈的作用範圍之內,那麼b炸彈也會被引爆,問將所有炸彈都引爆需要的最小花費。

思路:把可以引爆的炸彈間連邊,建立有向圖;如果有環,使用tarjan演算法縮點染色(同環內可以相互引爆);找到入度為0的分量,找出其中花費最小的點作為引爆這個分量及其相連分量的點累加。

綜上所述,tarjan強連通縮點染色之後,找到度為0的節點,並且在其中找到花費最小的炸彈,累加即可。

具體的:在dfn[u] == low[v]時更新分量的最小花費

關於最小點基和最小權點基:最小點基,最小權點基(summer holiday hdu - 1827)(強連通分量的應用)

Tarjan演算法 縮點

我們這一篇是在已經了解tarjan演算法的基礎之上開始寫的,如果不了解的話,請先看大牛們 關於tarjan演算法的部落格。首先我們對於乙個有向無環的圖 dag 至少新增幾條邊才能使它變為強連通圖?我們很容易根據有向無環圖的性質得到,我們計算入度為零的點數為a,出度為零的點數為b,那麼我們至少需要新增...

tarjan演算法求scc 縮點

圖的遍歷 dfs 對於有向圖g中的任意兩個頂點u和v存在u v的一條路徑,同時也存在v u的路徑,我們則稱這兩個頂點強連通。以此類推,強連通分量就是某乙個分量內各個頂點之間互相連通。簡單來說,就是有向圖內的乙個分量,其中的任意兩個點之家可以互相到達。求有向圖內部強連通分量的方法大概有2種 tarja...

強連通分量及縮點tarjan演算法解析

再次深搜 此時 stack 發現綠邊指向了已經遍歷過的點4 是上述的2種邊之一 而4在棧中 4點與6點是父子關係 該邊為後向邊 4 6的路徑上的點都是環。int num n top 0 int u stack.top while u 4 num top u 如此就能把stack中 4 6路徑上的點轉...