目錄
題目描述
輸入格式
輸出格式
思路:**:
給定乙個
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...