tarjan强联通分量和缩点
https://www.cnblogs.com/dx123/p/16320476.html
https://www.cnblogs.com/dx123/p/16320478.html
Luogu P3387 【模板】缩点
#include<bits/stdc++.h>
using namespace std;
const int N=10010;
int dfn[N],low[N],tot;
int stk[N],instk[N],top;
int scc[N],siz[N],cnt;
vector<int> e[N], ne[N];// e 原始图 , ne 新图
int n,m,u,v;
int w[N], nw[N];//w 是原始的权值,nw 是新的权值
int dp[N];
void tarjan(int x){
dfn[x] = low[x] = ++tot;
stk[++top] = x;
instk[x] = 1;
for (int y : e[x]) {
if (!dfn[y]) { // y is not visited
tarjan(y);
low[x] = min(low[x], low[y]); // update low when returning to x
} else if (instk[y]) { // y is visited and in stack
low[x] = min(low[x], dfn[y]); // update low when in x
}
}
if (dfn[x] == low[x]) { // x is the root of SCC
int y; ++cnt;
do {
y = stk[top--];
instk[y] = 0;
scc[y] = cnt; // SCC number
++siz[cnt]; // SCC size
} while (y != x);
}
}
int main()
{
cin >> n >> m;
for(int i = 1; i <= n; i++) {
cin >> w[i];
}
while(m--) {
cin >> u >> v;
e[u].push_back(v);
}
for(int i=1; i<=n; i++) {
if(!dfn[i]) {
tarjan(i);
}
}
// 缩点,建新图
for(int i=1; i<=n; i++) {
nw[scc[i]] += w[i]; // 将原始权值累加到新的权值上
for(auto j : e[i]) {
if(scc[i] != scc[j]) { // 如果 i 和 j 不在同一个强连通分量中
ne[scc[i]].push_back(scc[j]); // 在新图中添加边
}
}
}
// * 注意到强联通分量从大到小编号就已经是拓扑排序过的顺序,所以可以直接dp
for(int i=cnt; i>=1; i--) {
if(dp[i] == 0) //起点
dp[i] = nw[i];
for(auto j : ne[i]) {
dp[j] = max(dp[j], dp[i] + nw[j]); // 更新 dp 数组
}
}
int ans = 0;
for(int i=1; i<=cnt; i++) {
ans = max(ans, dp[i]); // 找到最大的权值
}
cout << ans << endl; // 输出结果
return 0;
}


浙公网安备 33010602011771号