洛谷p1352没有上司的舞会 树形dp

来源:互联网 发布:域名备案是什么部门 编辑:程序博客网 时间:2024/06/06 03:23

一看有点选数的味道……
比较好想 增维打标记来表示选与不选 应该是这题的标准解法了
目标函数: 选node结点的最大值表示为dp[node][1]
不选就是dp[node][0]
边界:一个while循环找到根 递归到一个结点时,把dp[node][1]初始化为r[node] dp[node][0]就是0了
状态转移方程:dp[node][1]=每个儿子的dp[儿子][0]之和
dp[node][0]=max(dp[i][1],dp[i][0])
梗:存r的时候把下标弄成0开始……遂爆炸

传送门:https://www.luogu.org/problemnew/show/P1352

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>using namespace std;const int maxn = 6007;int fa[6007], dp[maxn][2],n;bool visit[maxn];int r[maxn];/*struct  edge {    int v, next;}e[maxn*2];int p[maxn],eid=0;int n, r[maxn];int d[maxn][2];void dfs(int u) {//这是已经选了一个以后    int v = e[u].v;    for (int i = p[u]; i; i = e[i].next) {    }}void ins(int u, int v) {    e[++eid].v = v;    p[u] = eid;    e[eid].next = p[u];}*/void tree_dp(int node) {    visit[node] = 1;    dp[node][0] = 0;    dp[node][1] = r[node];    for (int i = 1; i <= n; i++) {        if (!visit[i] && fa[i] == node) {//i为node的子节点  应该有更优            tree_dp(i); //递归算儿子            dp[node][1] += dp[i][0];    //选择爸爸,就不必选择儿子            dp[node][0] += max(dp[i][1], dp[i][0]);//不选爸爸,选择选不选儿子        }    }}int main() {    int root;   //根结点    cin >> n;    int x, y;    memset(fa, 0, sizeof(fa));    memset(visit, 0, sizeof(visit));    for (int i = 1; i<=n; i++) cin >> r[i];    while (scanf("%d %d", &x, &y), x || y) {        fa[x] = y;      //k是l的直接上司        root = y;    }    //读入    //接下来寻找根结点    while (fa[root]) {        root = fa[root];    }    tree_dp(root);    printf("%d\n", max(dp[root][0], dp[root][1]));    return 0;}
原创粉丝点击