骑士 给一点权基环树森林,每个点和其出度不同选,求选出点权和之最大值。
树上 DP。 按基环树的套路先判环,尔后从成环点及其父节点出发分别舞会1,并取最大值相加。但有两个坑点:标注 What Ghost
处一句不能略,因为 cc[in][1]
状态无效;std::vector
存图会卡一个点。
#include <cstdio>
#include <algorithm>
#define F(z, u, v) for(int z = (u), zz = (v); z <= zz; z++)
typedef long long int LINT;
const int MAXN = 1000001;
int n, w[MAXN], pa[MAXN]; bool vis[MAXN]; LINT ans = 0;
int hd[MAXN], po[MAXN];
LINT Dfs(int cr, int in) {
static LINT cc[MAXN][2];
vis[cr] = true; cc[cr][0] = 0; cc[cr][1] = w[cr];
for(int i = hd[cr]; i; i = po[i])
if(i != in) { Dfs(i, in);
cc[cr][0] += std::max(cc[i][0], cc[i][1]); cc[cr][1] += cc[i][0]; }
else cc[in][1] = -MAXN; // What ghost?!
return std::max(cc[cr][0], cc[cr][1]); }
int main() {
scanf("%d", &n);
F(i, 1, n) { scanf("%d%d", w + i, pa + i);
po[i] = hd[pa[i]]; hd[pa[i]] = i; }
F(i, 1, n) if(!vis[i]) for(int j = i;; j = pa[j]) {
vis[j] = true; if(vis[pa[j]]) {
ans += std::max(Dfs(j, j), Dfs(pa[j], pa[j])); break; }}
printf("%lld", ans); }
- “没有上司的舞会”问题,转移方程为 dp[i][0]=∑k∈son(i)maxdp[k][0],dp[k][1],dp[i][1]=∑k∈son(i)dp[k][0] d p [ i ] [ 0 ] = ∑ k ∈ s o n ( i ) max d p [ k ] [ 0 ] , d p [ k ] [ 1 ] , d p [ i ] [ 1 ] = ∑ k ∈ s o n ( i ) d p [ k ] [ 0 ] 。 ↩