Tarjan演算法 縮點

2021-08-17 22:03:53 字數 2793 閱讀 7366

我們這一篇是在已經了解tarjan演算法的基礎之上開始寫的,如果不了解的話,請先看大牛們

關於tarjan演算法的部落格。

首先我們對於乙個有向無環的圖(dag),至少新增幾條邊才能使它變為強連通圖?我們很容易根據有向無環圖的性質得到,我們計算入度為零的點數為a,出度為零的點數為b,那麼我們至少需要新增的邊數為max(a,b),如果只有乙個點的話,我們不需要新增任何邊。

那麼我們怎麼把乙個圖轉換為dag呢,因為上面給出的圖可能存在環,那麼我們就會想到把已經組成全連通的子圖轉換成乙個點來看,那麼我們最終的圖就不會包含環了。

好了,解決這類問題的思路已經想好了,下面我們來進行求解:

我們使用tarjan演算法求解出強連通分量之後,我們使用乙個belong陣列將同乙個連通分量的點分配相同的數值,存放在belong陣列中,然後我們再次遍歷一遍點,然後這次操作的是belong陣列中對應的數值,只有把不屬於同於個連通分量的邊新增到新的圖中,並且根據這些邊來計算每個縮點的入度以及出度。

//不怕別人比你聰明,就怕別人比你聰明還比你努力

#include#include#include#include#include#include#include #include #include#define inf 0x3f3f3f3f

using namespace std;

const int maxn = 1000;

struct node

edge1[maxn],edge2[maxn]; //edge1表示還沒有縮點之前的圖,edge2表示縮點之後的圖的連通關係

int head[maxn];

int dfn[maxn],low[maxn];

int vis[maxn],stact[maxn];

int belong[maxn],num[maxn];

//belong表示每個點屬於的縮完之後的哪乙個點,num表示每乙個縮點裡面有多少個點

int cnt,tot,index,now;

void add(int x,int y,node* edge)

void tarjan(int x)

else if(vis[v])

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

}if(low[x] == dfn[x])

while(x != stact[index+1]);

printf("\n");

}return ;

}int main()

for(int i = 1;i <= n;i ++)

if(!dfn[i])

tarjan(i);

int inde[maxn];//表示每個縮點的入讀

int outde[maxn];//每個縮點的出度

//縮點完成之後,我們就一定沒有環的存在

memset(head,-1,sizeof(head));

int u,v;

for(int i = 1;i <= m;i ++)

}int a = 0,b = 0;

//分別計算所的縮點中,入度和出度為0的數目

for(int i = 1;i <= now;i ++)

if(now == 1)

//如果所有的縮點只有乙個,則不需要新增新邊

printf("0\n");

else

printf("%d\n",max(a,b));

}

6 8

1 31 2

2 43 4

3 54 6

4 15 6

我們的測試資料如上,答案是需要新增一條邊。

我們來看乙個例題:poj 2186

我們要想知道有多說少被全部的認為是受歡迎的,我麼先要將他們進行完縮點之後,只有其他的點都可以到達的點才是被其它都歡迎的點。

//不怕別人比你聰明,就怕別人比你聰明還比你努力

//因為和上面程式很類似,所以沒有寫注釋....

include#include#include#include#include#include#include #include #include #include#define inf 0x3f3f3f3f

using namespace std;

const int maxn = 51000;

struct node

edge1[maxn];

int head[maxn];

int dfn[maxn],low[maxn];

int vis[maxn],stact[maxn];

int belong[maxn],num[maxn];

int cnt,tot,index,now;

int n,m;

void add(int x,int y,node* edge)

void tarjan(int x)

else if(vis[v])

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

}if(low[x] == dfn[x])

while(x != stact[index+1]);

}return ;

}void init()

}int main()

; for(int i = 1;i <= m;i++)

}int ans = 0;

for(int i =1;i <= now;i ++)

ans = num[i];}}

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

return 0;

}

Tarjan縮點 SPFA 縮點

洛谷p3387縮點 tarjan spfa求dag上單源最短路模板題 用tarjan在原圖上求scc 縮點 用縮點之後的scc建乙個有向無環圖 scc權為此scc內所有點點權和 在新建的dag上將scc權視為邊權跑spfa 求scc 1 到scc n 的最長路即為所求答案 include inclu...

tarjan演算法求scc 縮點

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

Tarjan 縮點 模板

縮點以後,整張圖變為dag 有向無環圖 此時運用拓撲排序 求出度入度就可以完成許多事 題目 include include include include include include define ll long long using namespace std const int maxn 1...