1. 程式人生 > 其它 >【模板】縮點(tarjan + 拓撲排序)

【模板】縮點(tarjan + 拓撲排序)

技術標籤:演算法# 圖論

題目連結

題目描述

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

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

輸入格式

第一行兩個正整數 n, m

第二行 n 個整數,依次代表點權

第三至 m + 2 行,每行兩個整數 u, v,表示一條 u → v 的有向邊。

輸出格式

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

輸入輸出樣例

輸入

2 2
1 1
1 2
2 1

輸出

2

#include<bits/stdc++.h>
using namespace std;
const
int maxn = 1e5 + 10; int n, m, cnt, s, sum, num; // n 個點,m 條邊,cnt 強連通分量 int K[maxn], head[maxn], h[maxn], p[maxn], dis[maxn], in[maxn]; // K 表示每個節點所屬的強聯通分量 int DFN[maxn], low[maxn]; // DFN[i] 表示 i 點的進入時間,low[i]表示從 i 點出發,所能訪問到的最早的進入時間 bool inS[maxn]; stack<int> S; struct edge{ int from, to, next;
}edge1[maxn * 10], edge2[maxn * 10]; void add(int x, int y) { edge1[++sum].next = head[x]; edge1[sum].from = x; edge1[sum].to = y; head[x] = sum; } void Tarjan(int x) { num++; DFN[x] = low[x] = num; // num 表示在棧中的編號 inS[x] = 1; S.push(x); for(int i = head[x]; i; i = edge1[i].next){ // 搜尋相連節點 int
s = edge1[i].to; if(!DFN[s]){ // 沒搜尋過 Tarjan(s); low[x] = min(low[x], low[s]); // 更新所能到的上層節點 } else if(inS[s]){ // 在棧中 low[x] = min(low[x], DFN[s]); // 到棧中最上端的節點 } } if(low[x] == DFN[x]){ int y; while(1){ y = S.top(); inS[y] = 0; S.pop(); K[y] = x; if(x == y) break; p[x] += p[y]; } } return ; } int tuopu() // 拓撲排序 { queue<int> q; int tot = 0; for(int i = 1; i <= n; i++){ if(K[i] == i && !in[i]){ q.push(i); dis[i] = p[i]; } } while(!q.empty()){ int k = q.front(); q.pop(); for(int i = h[k]; i; i = edge2[i].next){ int v = edge2[i].to; dis[v] = max(dis[v], dis[k] + p[v]); in[v]--; if(in[v] == 0) q.push(v); } } int ans = 0; for(int i = 1; i <= n; i++) ans = max(ans, dis[i]); return ans; } int main() { cin >> n >> m; for(int i = 1; i <= n; i++) cin >> p[i]; for(int i = 1; i <= m; i++){ int u, v; cin >> u >> v; add(u, v); } for(int i = 1; i <= n; i++){ if(!DFN[i]) Tarjan(i); } for(int i = 1; i <= m; i++){ int x = K[edge1[i].from], y = K[edge1[i].to]; if(x != y){ edge2[++s].next = h[x]; edge2[s].to = y; edge2[s].from = x; h[x] = s; in[y]++; } } cout << tuopu() << endl; return 0; }