我們按照複雜程度來討論不同的tarjan演算法變形的差異.
但此時只是有所區分的將所有的點劃分為乙個個的強連通分量, 尚且沒有縮點. 上面這個功能實現起來最簡單.
它的tarjan函式內****的.
void tarjan(int u)
else
if (in_stack[v]) // 還剩下一種不在棧中但是已經訪問過的情況,是其他連通分量的
}if (dfn[u] == low[u]) while (stack[--top + 1] != u);
cout
<< endl;
}}
在tarjan函式內部他們的主要區別是當dfn[u] == low[u]
的這一段
if (dfn[u] == low[u]) while (now != u);
}
所以我們可以有下面這段**,setnow
代表縮點後的新圖.
for (int i = 1; i <= n; ++i)
}
通過to
陣列關聯起原圖和縮點後圖的點, 從而建立新圖.
這樣, 通過dfn[u] == low[u]
處的修改, 以及結合to
陣列建立新圖的過程, 就實現了tarjan演算法的縮點.
上面的to
陣列保留, 看下面這段**
for (int i = 1; i <= n; ++i)
}}
一二層迴圈遍歷之前所有的邊, 裡面乙個條件語句,判斷邊的兩端點是否指向同乙個縮點, 如果不是, 那麼他們在to
陣列中所指向的新的結點也將作為一條邊.利用to
陣列可以快速方便的獲取新圖中的入度和出度, 這樣的話要知道入度和出度就無需建立新圖.
看洛谷上的這道題 傳送門
此題是以點為權值而非邊, 但做法是基本差不多的. 都是dp演算法.
dp函式是這樣
int dp(int u)
dp[u] += val_now[u];
return dp[u];
}
狀態轉移方程:dp[i] = max + val_now[i]
區別於邊為權值的方程:dp[i] = max
ac**
#include
#include
#include
#include
#include
using
namespace
std;
const
int maxn = 10005;
stack
sta;
vector
g[maxn];
set now[maxn];
int n, m, index = 0, cnt = 0, ans = 0;
int to[maxn], dfn[maxn] = {}, low[maxn];
int dp[maxn] = {}, val[maxn], val_now[maxn] = {};
bool in_stack[maxn] = {};
void tarjan(int u)
else
if (in_stack[v]) low[u] = min(low[u], low[v]);
}if (dfn[u] == low[u]) while (now != u);
}}int dp(int u)
dp[u] += val_now[u];
return dp[u];
}int main()
for (int i = 1; i <= n; ++i)
if (dfn[i] == 0) tarjan(i);
for (int i = 1; i <= n; ++i)
}for (int i = 1; i <= n; ++i)
for (int i = 1; i <= cnt; ++i)
ans = max(ans, dp[i] = dp(i));
cout
<< ans;
}
我認為tarjan演算法縮點的核心就是to
陣列. Tarjan演算法 縮點
我們這一篇是在已經了解tarjan演算法的基礎之上開始寫的,如果不了解的話,請先看大牛們 關於tarjan演算法的部落格。首先我們對於乙個有向無環的圖 dag 至少新增幾條邊才能使它變為強連通圖?我們很容易根據有向無環圖的性質得到,我們計算入度為零的點數為a,出度為零的點數為b,那麼我們至少需要新增...
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...