學習了tarjan算法,覺得這個算法真的是挺強大的,然而蒟蒻並不會用 ,先學習着寫一篇博客作爲記錄。
學習tarjan的點覺得主要在於兩個數組的理解—— 數組
數組,用於記錄序,也就是這個點最早什麼時候被dfs搜索到。
數組,用於記錄其及其子樹中的點能回溯到的點的最小序
這兩個數組引出了很多很多應用
tarjan模板
const int maxn = 1e5+5;
struct Edge{
int u,v,nxt;
}edge[maxn];
int head[maxn],tot;
inline void addedge(int u,int v){
edge[++tot] = {u,v,head[u]};
head[u] = tot;
}
bool vis[maxn];
int dfn[maxn],sta[maxn],low[maxn],stalen,num,color[maxn],dfnnum;
void tarjan(int u){
dfn[u] = low[u] = ++dfnnum;
sta[stalen++] = u; vis[u] = true;
for(int i = head[u]; ~i; i = edge[i].nxt){
Edge &e = edge[i];
if(!dfn[e.v]){
tarjan(e.v);
low[u] = min(low[u],low[e.v]);
}else if(vis[e.v]) low[u] = min(low[u],vis[e.v]);
}
}
應用
1.求強連通分量
- 強連通分量的定義:
有向圖強連通分量:在有向圖GG中,如果兩個頂點間()有一條從到 的有向路徑,同時還有一條從到 的有向路徑,則稱兩個頂點強連通。如果有向圖的每兩個頂點都強連通,稱是一個強連通圖。有向圖的極大強連通子圖,稱爲強連通分量。 ——百度百科
例如
如何求一個有向圖中的強連通分量呢?
即
原因還是要從和的含義來分析,上面我們提到:
- 數組,用於記錄序,也就是這個點最早什麼時候被dfs搜索到。
- 數組,用於記錄其及其子樹中的點能回溯到的點的最小序
- 這說明了點及點之下的所有子節點沒有邊是指向u的祖先的了,即我們之前說的點與它的子孫節點構成了一個最大的強連通圖即強連通分量
然後呢,不斷的出棧頂元素直到 u == cur,所有被出棧的元素都屬於同一個強連通分量。
代碼:
const int maxn = 1e5+5;
struct Edge{
int u,v,nxt;
}edge[maxn];
int head[maxn],tot;
inline void addedge(int u,int v){
edge[++tot] = {u,v,head[u]};
head[u] = tot;
}
bool vis[maxn];
int dfn[maxn],sta[maxn],low[maxn],stalen,num,color[maxn],dfnnum;
void tarjan(int u){
dfn[u] = low[u] = ++dfnnum;
sta[stalen++] = u; vis[u] = true;
for(int i = head[u]; ~i; i = edge[i].nxt){
Edge &e = edge[i];
if(!dfn[e.v]){
tarjan(e.v);
low[u] = min(low[u],low[e.v]);
}else if(vis[e.v]) low[u] = min(low[u],vis[e.v]);
}
if(dfn[u]==low[u]){
++num; int cur;
do{
cur = sta[--stalen];
vis[cur] = 0;
color[cur] = num; // 染色,同一個顏色的爲一個強連通分量
}while(u!=cur);
}
}
我們可以來做一個簡單的模擬即可明白具體過程,以及算法的正確性
模板題練手
P2341 [HAOI2006]受歡迎的牛|【模板】強連通分量
2. 縮點
簡單來說,一個強連通分量內的點都可以互相可達,舉信息傳遞的例子來說,如果任意選擇一個強連通分量內的點作爲信息源,在這個強連通分量內的其他點都可以收到信息,於是就引出了一個縮點的概念(縮點在很多圖論題目中應用很廣泛,可以使得一些有向有環圖變成有向無環圖,於是就可以用到拓撲排序等等之類的在DAG上可以用到的算法)
因此縮點是強連通分量的一個應用 (我認爲
模板題:P3387 【模板】縮點
然後分析一下這道題目爲什麼要用到縮點呢,看一下題意
給定一個n個點m條邊有向圖,每個點有一個權值,求一條路徑,使路徑經過的點權值之和最大。你只需要求出這個權值和。
允許多次經過一條邊或者一個點,但是,重複經過的點,權值只計算一次。
對於一個強聯通分量來說,如果可以走進這個強連通分量,那麼這個分量裏的點都要走一遍(因爲這樣是最優的,那麼我們就可以把整個連通分量縮小成一個點,並且這個點的點權爲所有點的點權之和)
然後把這些點再重新建邊,跑一遍記搜或者dp(DP好像需要用拓撲序)就可以了
3.割點
在無向連通圖中,如果將其中一個點以及所有連接該點的邊去掉,圖就不再連通,那麼這個點就叫做割點(cut vertex / articulation point)。(割點一般對於無向圖來說)
找割點
當 ,此時就爲割點了
總的來說…這些都是一些基礎知識,對於題目來說要靈活使用才能做出題目