洛谷 縮點 tarjan演算法模板題

2021-10-25 11:38:36 字數 1904 閱讀 9453

目錄

題目描述

輸入格式

輸出格式

思路:**:

給定乙個 

n個點 

m 條邊有向圖,每個點有乙個權值,求一條路徑,使路徑經過的點權值之和最大。你只需要求出這個權值和。

允許多次經過一條邊或者乙個點,但是,重複經過的點,權值只計算一次。

第一行兩個正整數 n,m

第二行 

n個整數,依次代表點權

第三至 

m+2行,每行兩個整數 u,v

,表示一條 u→v

的有向邊。

共一行,最大的點權之和。

強連通區域:有向圖中,區域內任何兩點都可以互相到達。如果將所有的強連通區域看作乙個點,將整個區域的點全部疊加到乙個點上。(因為到達乙個點後,這個區域都可以到達(題目很友好,可以重複經過點和邊))。

求強連通區域的方法:tarjan演算法。可以有效地將圖劃分為乙個或多個強連通區域,時間複雜度o(n+m)。

這樣就轉化為了無環的有方向的圖,可以理解為乙個只能向下指向的樹。

這時候就可以在樹上用記憶化搜尋,經過乙個點時,賦值給dp,任何遍歷所有子樹,dp加上所有子樹中最大的即可。

#include#include#include#include#include#include#include#include#include#includeusing namespace std;

typedef long long ll;

const int maxn = 1e5+50;

int dfn[maxn],low[maxn];

//dfn:該點是被遍歷的第幾個

//low:該點能到達的最小dfn

int sum[maxn];

//記錄每個強連通分量縮合而成的value

bool vis[maxn];

//記錄已被遍歷

int head[maxn],tot = 0;

int n,m;

int cnt = 0;

int num = 0;

int ans = 0;

int group[maxn];

//各點所在強連通分量組號

int val[maxn];

int x[maxn],y[maxn];

int dp[maxn];

stackst;

struct ededge[maxn];

void ini()

void add(int u,int v)

void tarjan(int u)

else if(vis[v])           low[u] = min(low[u],low[v]);

//否則的話,如果在棧中(意味著已經被遍歷dfn[v]進棧並且還未出棧vis[v])

//出棧意味著是一組強連通分量,這樣就意味著v未與別人組成強連通分量。

//其餘情況就是已經完全的組成了強連通分量。

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

st.pop();}}

}void solve(int x)

dp[x]+=maxs;

}int main()

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

if(!dfn[i])                  tarjan(i);//有可能存在不連通的,遍歷所有點。實質上是遍歷數是連通分支數

ini();//清空圖,以便重建

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

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

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

}cout << ans << endl;

return 0;

}

Tarjan 縮點 模板

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

tarjan 模板 縮點

傳送門 首先呢,tarjan找乙個圖的強連通分量是基於對圖的dfs的。這中間開了乙個dfn代表dfs序,還有個low代表該節點在dfs形成的樹中能到達的最近的根。然後分情況進行更新 一會兒看我 吧 為了記錄乙個強聯通分量,我們還要在開乙個棧來儲存當前查詢的強連通分量。如果low x dfn x 那就...

Tarjan縮點 洛谷P2341

傳送門 這題很簡單,不知道為什麼是提高組的題.主要思路就是先tarjan縮點,然後在dag上找出度為0的點,如果只有乙個出度為0的點,那麼這個點就是的大小就是受歡迎的牛的數目。如果有兩個及以上個點的出度為0,那麼不存在明星牛。下面是 include using namespace std const...