P3387 模板 縮點 TJ

2022-07-23 18:33:17 字數 1538 閱讀 7384

題目鏈結

模板題,先使用 \(tarjan\) 進行縮點,然後重新建邊,最後拓撲排序即可

在有向圖g中,對於點集v'∈v, 點集中的任意兩點都可達,則稱v'為強連通

在有向圖中,\(dfs\) 時,我們需要維護 \(dfn\) 和 \(low\),目的在於把所有的強連通分量縮成乙個點(因為題目裡說可以重複走,而強連通分量裡兩點都可以到達)

設 \(dfn_i\) 為遍歷到當前節點 \(i\) 的時間戳,\(low_i\) 為當前節點 \(i\) 能回溯到的最早節點,

當 \(dfn_i = low_i\) 時說明以 \(i\) 為根形成了強連通分量,

此時我們可以用棧來維護當前強連通分量裡的所有點。

此時縮點後的圖是乙個有向無環圖(強連通分量被縮成點),我們考慮使用拓撲排序求出最終的最長路徑

先將入度為 \(0\) 的點進入佇列,然後出隊,將可到達的點的入度減 \(1\) ,然後將當前入度為 \(0\) 點加入佇列,過程中可以 \(dp\) 求出最長路徑

#include #include #include #include #include using namespace std;

const int maxn = 1e4 + 10;

const int maxm = 1e5 + 10;

queue s;

int sta[maxn] ,ind = 0;

vector c[maxn];

int in[maxn];

struct node edge[maxm];

int head[maxn] ,cnt = 0;

void add (int from ,int to)

int n ,m ,answ = 0;

int dis[maxn] ,dis_[maxn];

int tot = 0 ,times = 0;

int dfn[maxn] ,low[maxn] ,ins[maxn] = ,vis[maxn];

void tarjan (int u)

else if (ins[v])

low[u] = min (low[u] ,dfn[v]);

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

int tot_ = 0;

int dp[maxn];

void toposort ()

} while (! s.empty())

} }}int main ()

for (int q = 1;q <= n;++ q)//tarjan

if (! dfn[q]) tarjan (q);

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

} toposort ();//拓撲排序

for (int q = 1;q <= tot;++ q)

answ = max (answ ,dp[q]);

printf ("%d\n",answ);

return 0;

}

P3387 模板 縮點

r es ul tresult result h yp erli nk hyperlink hyperl ink de scri ptio ndescription descri ptio n 給定一張n nn個點,m mm條邊的有向圖,點有點權 找出一條路徑使得經過的點的權值和最大,點和邊可以重複...

P3387 模板 縮點

縮點 dp 給定乙個n個點m條邊有向圖,每個點有乙個權值,求一條路徑,使路徑經過的點權值之和最大。你只需要求出這個權值和。允許多次經過一條邊或者乙個點,但是,重複經過的點,權值只計算一次。輸入格式 第一行,n,m 第二行,n個整數,依次代表點權 第三至m 2行,每行兩個整數u,v,表示u v有一條有...

P3387 模板 縮點

題解 qwq論這個題我開了多少陣列qwq 因為每個點走過多次權值只會計算1次 簡化問題 把題目給出的有向圖縮點,成為有向無環圖,然後拓撲排序跑最長路 首先tarjan縮點 然後強連通分量連邊 下面跑拓撲排序,入度為0的強連通分量 first 然後 dis 計算到達這個強連通分量時的最大權值 感覺這裡...