Tarjan+dp
这里的题意解释一下: 给你一个有向图,从任意一个节点出发(注意,这里只能前进不能回溯), 每一个节点都有一个权值,可正可负,可取可不取(这个负值几乎没啥意义,负数一概不取就行了),直到没有可以 可以走的节点时,权值的和最大是多少。(注意!!不能回退)题意弄清楚之后,这道题就不难做了。
首先是用Tarjan缩点(因为缩点之后,图会变成一个森林,比较容易操作),每个缩点内的正权值全部加起来,作为这个缩点的权值。
对于一颗树来说,从根节点出发无疑是最优的,所以我们要分别从所有入度为0的点出发做dfs,用dp数组记录从该节点出发能得到的最大总权值是多少,如果下次再经过这个节点时就不需要向下dfs了
直接取节点的dp值就行了。
这里需要注意的一点是, Tarjan算法中,low[u] = min(low[u], dfn[v]) 一定要判断 v 是否在栈内。
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int MaxnN = 1e4+10;
const int MaxnE = 2e5+10;
struct Edge {
int v, next;
} edge[MaxnE], vedge[MaxnE];
int h[MaxnN], edge_cnt;
int vh[MaxnN], vedge_cnt;
int Stack[MaxnN], Top;
int scc, indx;
int dfn[MaxnN], low[MaxnN], num[MaxnN], dp[MaxnN];
int cost[MaxnN], vcost[MaxnN], indeg[MaxnN];
void add(int u, int v) {
edge[edge_cnt].v = v;
edge[edge_cnt].next = h[u];
h[u] = edge_cnt++;
}
void vadd(int u, int v) {
vedge[vedge_cnt].v = v;
vedge[vedge_cnt].next = vh[u];
vh[u] = vedge_cnt++;
}
void Tarjan(int u) {
dfn[u] = low[u] = ++indx;
Stack[Top++] = u;
for(int i = h[u]; i != -1; i = edge[i].next) {
Edge e = edge[i];
if(!dfn[e.v]) {
Tarjan(e.v);
low[u] = min(low[u], low[e.v]);
} else if(!num[e.v])low[u] = min(low[u], dfn[e.v]);
}
if(dfn[u] == low[u]) {
scc++;
int v;
do {
v = Stack[--Top];
num[v] = scc;
vcost[scc] += max(0, cost[v]);
} while(v != u);
}
}
void dfs(int u) {
if(dp[u]) return;
int sum = 0;
for(int i = vh[u]; i != -1; i = vedge[i].next) {
Edge e = vedge[i];
if(!dp[e.v]) dfs(e.v);
sum = max(sum, dp[e.v]);
}
dp[u] = sum+vcost[u];
}
int main(void)
{
int n, m;
while(scanf("%d%d", &n, &m) != EOF) {
for(int i = 0; i <= n; ++i) h[i] = -1;
edge_cnt = 0;
for(int i = 0; i < n; ++i) scanf("%d", &cost[i]);
int u, v;
for(int i = 1; i <= m; ++i) {
scanf("%d%d", &u, &v);
add(u, v);
}
scc = indx = Top = 0;
for(int i = 0; i < n; ++i) dfn[i] = low[i] = vcost[i] = num[i] = 0;
for(int i = 0; i < n; ++i) {
if(!dfn[i]) Tarjan(i);
}
for(int i = 1; i <= scc; ++i) {
indeg[i] = 0; vh[i] = -1;
}
vedge_cnt = 0;
for(int i = 0; i < n; ++i) {
for(int j = h[i]; j != -1; j = edge[j].next) {
Edge e = edge[j];
if(num[e.v] != num[i]) {
indeg[num[e.v]]++;
vadd(num[i], num[e.v]);
}
}
}
for(int i = 1; i <= scc; ++i) dp[i] = 0;
int ans = 0;
for(int i = 1; i <= scc; ++i) {
if(indeg[i] == 0) {
dfs(i);
ans = max(ans, dp[i]);
}
}
printf("%d\n", ans);
}
return 0;
}
浙公网安备 33010602011771号