一个经典的图DP,首先对无向图进行强联通分量缩点变成DAG,这样就可以在DAG上用拓扑序做DP
需要注意的是点权是有负数的情况为此WA无数次
附代码供后人参考
#include <cstdio>
#include <algorithm>
#include <cstring>
#define DEBUG(x) cout << #x << " " << x << endl;
using namespace std;
class scc
{
private:
const static int V = 50001;
const static int E = 150000;
struct edge
{
int v;
edge *nxt;
} pool[E * 3], *g[V], *pp, *gscc[V];
int n, m, st[V], top;
int val[V], valscc[V], dp[V];
int tms[V], pt;
bool reach[V];
int dfn[V], low[V], idx[V];
int cnt, depth;
void dfs(int x);
void build_newgraph();
void addnewedge(int u, int v)
{
pp->v = v;
pp->nxt = gscc[u];
gscc[u] = pp++;
}
void toposort(int x);
public:
void addedge(int u, int v)
{
pp->v = v;
pp->nxt = g[u];
g[u] = pp++;
}
void initialize(int n);
void solve();
} g;
void scc::initialize(int n)
{
this->n = n;
memset(g, 0, sizeof (g));
memset(reach, false, sizeof (reach));
memset(dfn, 0, sizeof (dfn));
for (int i = 0; i < n; i++)
scanf("%d", &val[i]);
pp = pool;
depth = pt = top = cnt = 0;
}
void scc::dfs(int x)
{
st[++top] = x;
int w;
dfn[x] = low[x] = ++depth;
for (edge *i = g[x]; i != NULL; i = i->nxt)
{
w = i->v;
if (reach[w])
continue;
else if (dfn[w] == 0)
{
dfs(w);
if (low[w] < low[x])
low[x] = low[w];
}
else if (dfn[w] < low[x])
low[x] = dfn[w];
}
if (low[x] == dfn[x])
{
cnt++;
do
{
w = st[top--];
idx[w] = cnt;
reach[w] = true;
}
while (w != x);
}
}
void scc::solve()
{
for (int i = 0; i < n; i++)
if (!reach[i])
dfs(i);
build_newgraph();
memset(reach, false, sizeof (reach));
for (int i = 1; i <= cnt; i++)
if (!reach[i])
toposort(i);
memset(dp, 0, sizeof (dp));
for (int i = 0; i < pt; i++)
{
int w = tms[i], tmp = 0;
dp[w] = valscc[w];
for (edge *j = gscc[w]; j != NULL; j = j->nxt)
tmp = max(tmp, dp[j->v]);
dp[w] += tmp;
}
int ans = dp[1];
for (int i = 2; i <= cnt; i++)
ans = max(ans, dp[i]);
printf("%d\n", ans);
}
void scc::toposort(int x)
{
reach[x] = true;
for (edge *i = gscc[x]; i != NULL; i = i->nxt)
if (!reach[i->v])
toposort(i->v);
tms[pt++] = x;
}
void scc::build_newgraph()
{
memset(gscc, 0, sizeof (gscc));
memset(valscc, 0, sizeof (valscc));
for (int i = 0; i < n; i++)
if(val[i] > 0)
valscc[idx[i]] += val[i];
for (int i = 0; i < n; i++)
for (edge *j = g[i]; j != NULL; j = j->nxt)
if (idx[i] != idx[j->v])
addnewedge(idx[i], idx[j->v]);
}
int main()
{
scc g;
int n, m, vfrom, vto;
while (scanf("%d %d", &n, &m) == 2)
{
g.initialize(n);
for (int i = 0; i < m; i++)
{
scanf("%d %d", &vfrom, &vto);
g.addedge(vfrom, vto);
}
g.solve();
}
return 0;
}