CodeVS 1380 没有上司的舞会(树形DP)

又是一道树形DP,做了两道树型DP,现在来总结一下.
在这两题中,有一个共同点,就是为任何一个子树设置一组状态变量。在本题中,设置状态变量A、B,然后导出了状态变量转换方程,再使用DFS对状态变量逐次求解,就做出了这道题。
总的来说,本题还是比较简单的。

/*
1380 没有上司的舞会
时间限制: 1 s
空间限制: 128000 KB
题目等级 : 钻石 Diamond
题解
题目描述 Description
Ural大学有N个职员,编号为1~N。他们有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点的直接上司。每个职员有一个快乐指数。现在有个周年庆宴会,要求与会职员的快乐指数最大。但是,没有职员愿和直接上司一起与会。

输入描述 Input Description
第一行一个整数N。(1<=N<=6000)
接下来N行,第i+1行表示i号职员的快乐指数Ri。(-128<=Ri<=127)
接下来N-1行,每行输入一对整数L,K。表示K是L的直接上司。
最后一行输入0,0。

输出描述 Output Description
输出最大的快乐指数。

样例输入 Sample Input
7
1
1
1
1
1
1
1
1 3
2 3
6 4
7 4
4 5
3 5
0 0

样例输出 Sample Output
5

思路
设置任何一个节点拥有两个属性:
A:如果包括该节点,最大欢乐度
B:如果不包括该节点,最大欢乐度

那么答案则为
max(root.A,root.B);

然后对于任何一个节点R,认为他的所有儿子为C1、C2。。。。。。

可以得到
R.A = R.Num + C1.B + C2.B + .....
R.B = max(C1.A,C1.B) + max(C2.A,C2.B) + .......

*/

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;


struct node{
    int child;
    node* next;
    node(int _child = 0, node* _next = NULL){//认为0为nil
        child = _child;
        next = _next;
    }
};

node *list[7000];

int Num[7000];
int A[7000];
int B[7000];

void DFS(int now, int N){
    int i, j;
    node* tmp;
    for (tmp = list[now]; tmp != NULL; tmp = tmp->next){
        DFS(tmp->child, N);
        A[now] += B[tmp->child];
        B[now] += max(A[tmp->child], B[tmp->child]);
    }
}
int solve(const int N,int root){
    int i, j, k;
    for (i = 1; i <= N; i++)A[i] = Num[i];
    memset(B, 0, sizeof(B));
    DFS(root, N);
    return max(A[root], B[root]);
}
int main(void){
    int N, i, j;
    while (cin >> N){
        memset(Num, 0, sizeof(Num));
        memset(list, 0, sizeof(list));

        for (i = 1; i <= N; i++){
            scanf("%d", Num + i);
        }
        int a, b,root = 1;
        scanf("%d %d", &a, &b);
        while (a != 0 && b != 0){
            node *tmp = new node(a, list[b]);
            list[b] = tmp;
            if (a == root)root = b;//寻找根节点
            scanf("%d %d", &a, &b);
        }
        cout << solve(N,root) << endl;
        for (i = 0; i < 7000; i++){
            while (list[i] != NULL){
                node* tmp = (list[i]);
                list[i] = list[i]->next;
                delete tmp;
            };
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值