我們這一篇是在已經了解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...