P1352 没有上司的舞会
原题链接:P1352 没有上司的舞会
一道经典的树形dp题。(我看未必)。由于这里是有向边的“树”,是一个典型的DAG(有向无环图),所以可以在拓扑排序中进行状态转移。注意状态转移方程中细微的区别。下面给出2种方法的代码。
状态转移方程的解释:f[][]第一维表示节点的标号,第二维只有2位,0表示选择不选此节点,1表示选择此节点。
拓扑排序:(v为父亲节点,u为儿子节点)
\(f[v][0] = \sum_\limits{(u,v)\in e} max(0, max(f[u][0], f[u][1]))\)
\(f[v][1] = \sum_\limits{(u,v)\in e} max(0, f[u][0])\)
// 拓扑序做法
#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 6005;
int n;
int r[N];
int h[N], e[N], ne[N], idx = 1;
int f[N][2];
// 节点入度,拓扑序的层数,根节点
int deg[N], d[N], root;
void insert(int a, int b) {
e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}
void topo_sort() {
// 队列
static int q[N], hh = 1, tt = 0;
for (int i = 1; i <= n; ++i) {
// 初始化dp边界
f[i][0] = 0, f[i][1] = r[i];
if (!deg[i]) q[++tt] = i, d[i] = 1;
}
while (hh <= tt) {
int u = q[hh++];
for (int i = h[u]; i; i = ne[i]) {
int v = e[i];
f[v][0] += max(0, max(f[u][0], f[u][1]));
f[v][1] += max(0, f[u][0]);
deg[v]--;
if (!deg[v]) q[++tt] = v;
if (d[v] < d[u] + 1) {
d[v] = d[u] + 1;
root = v;
}
}
}
}
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; ++i) scanf("%d", &r[i]);
for (int i = 1; i < n; ++i) {
int l, k;
scanf("%d%d", &l, &k);
// 建立儿子指向父亲的边
insert(l, k);
deg[k]++;
}
topo_sort();
printf("%d\n", max(f[root][0], f[root][1]));
}
树形dp:(u为父亲节点,v为儿子节点)
\(f[u][0] = max(f[u][0], f[u][0] + max(f[v][0], f[v][1]))\)
\(f[u][1] = max(f[u][1], f[u][1] + f[v][0])\)
// 树形dp做法
#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 6005;
int n;
int r[N], deg[N];
int h[N], e[N], ne[N], idx = 1;
int f[N][2];
void insert(int a, int b) {
e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}
void dfs(int u) {
f[u][0] = 0;
f[u][1] = r[u];
for (int i = h[u]; i; i = ne[i]) {
int v = e[i];
dfs(v);
f[u][0] = max(f[u][0], f[u][0] + max(f[v][0], f[v][1]));
f[u][1] = max(f[u][1], f[u][1] + f[v][0]);
}
}
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; ++i) scanf("%d", &r[i]);
for (int i = 1; i < n; ++i) {
int l, k;
scanf("%d%d", &l, &k);
// 建立父亲指向儿子的边
insert(k, l);
deg[l]++;
}
int root;
for (int i = 1; i <= n; ++i) if (!deg[i]) {
root = i;
break;
}
dfs(root);
printf("%d\n", max(f[root][0], f[root][1]));
}

浙公网安备 33010602011771号