洛谷2016 战略游戏 (0/1状态的普通树形Dp)
题意:
给出一个树,覆盖树上某一个点的花费为w[i],求树上每一条边至少有一个点覆盖的最小花费。
细节:
1.一条边的两端可以均被覆盖,但是不能存在一条边的两端都不被覆盖。
2.可能存在
分析:
对于一对儿子和父亲节点来说,要么儿子覆盖父亲不覆盖,父亲覆盖儿子不覆盖,或者是两者均被覆盖,所以不难发现对于父亲节点来说,若其被覆盖,则它的所有子孙可以被覆盖也可以不被覆盖,若其不被覆盖,则它的子孙必须可以被全部覆盖。
所以状态变得显然:dp[u][0/1] 表示节点 u 是否被覆盖的最小花费
再根据上方的分析条件转移如下:
dp[u][1] = ∑ min( dp[v][0] , dp[v][1] )
dp[u][0] = ∑ dp[v][1]
代码
#include<bits/stdc++.h>
#define MAXN 1505
using namespace std;
int f[MAXN][2], n;
vector<int> Right[MAXN];
void dfs(int u, int fa){
f[u][0]=0, f[u][1]=1;
for (int i=0; i<Right[u].size(); i++) {
int v=Right[u][i];
if (v==fa) continue;
dfs(v, u);
f[u][0]+=f[v][1];
f[u][1]+=min(f[v][0], f[v][1]);
}
}
int main(){
scanf("%d", &n);
for (int i=1, x, num; i<=n; i++) {
scanf("%d%d", &x, &num);
for (int j=1, y; j<=num; j++) {
scanf("%d", &y);
Right[x].push_back(y);
Right[y].push_back(x);
}
}
dfs(1, -1);
printf("%d\n", min(f[root][0], f[root][1]));
return 0;
}
Ps:
此题与 DAY2T3 的 44 分算法十分雷同,但是我死在了考场的一线上……