HDU 2412 Party at Hali-Bula 树形DP

Problem:
有一颗上下级关系的书,对于每一个节点来说,它和它的直系上级不能同时存在,问这棵树最多有多少个节点可以同时存在。
Solution:
对于每一颗子树,如果求出来这颗子树选和不选的两种情况的最大值,那么的父节点对应的就是,如果选父节点,那就把它所有子节点不选的最大值相加,如果不选父节点,那就把所有子节点中两种情况的最大值相加,对于选了的子节点的情况,看对应情况中是否有多种选择。
notes:
在树上的dp数据结构可以利用动态二维数组实现,对于每一个结点附一个权值,进行记忆化搜索。

#include<cstdio>
#include<iostream>
#include<sstream>
#include<cstdlib>
#include<cmath>
#include<cctype>
#include<string>
#include<cstring>
#include<algorithm>
#include<stack>
#include<queue>
#include<set>
#include<map>
#include<ctime>
#include<vector>
#include<fstream>
#include<list>
using namespace std;

typedef long long ll;
typedef unsigned long long ull;
#define ms(s) memset(s,0,sizeof(s))

const double PI = 3.141592653589;
const int INF = 0x3fffffff;

struct Node {
    int fw = 0, tw = 1;
    bool hasView = false, fhasSelect = false, thasSelect = false;
};

map<string, Node> nodes;
map<string, vector<string> > G;

int dp(string name, int flag) {//flag为1代表选,0代表不选
    Node &tnode = nodes[name];
    if(!tnode.hasView) {
        vector<string> &tg = G[name];
        for(int i = 0; i < tg.size(); i++) {
            tnode.tw += dp(tg[i], 0);
            if(nodes[tg[i]].fhasSelect)
                tnode.thasSelect = true;
            if(dp(tg[i], 0) == dp(tg[i], 1)) {
                tnode.fw += dp(tg[i], 0);
                tnode.fhasSelect = true;
            }
            else if(dp(tg[i], 1) > dp(tg[i], 0)) {
                tnode.fw += dp(tg[i], 1);
                if(nodes[tg[i]].thasSelect)
                    tnode.fhasSelect = true;
            }
            else {
                tnode.fw += dp(tg[i], 0);
                if(nodes[tg[i]].fhasSelect)
                    tnode.fhasSelect = true;
            }

        }
        tnode.hasView = true;
    }
    if(flag == 1)
        return tnode.tw;
    else
        return tnode.fw;
}

int main() {
//        freopen("/Users/really/Documents/code/input","r",stdin);
    //    freopen("/Users/really/Documents/code/output","w",stdout);
        ios::sync_with_stdio(false);

    int n;
    string boss, son, father;
    while(cin >> n) {
        if(n == 0)
            break;
        nodes.clear();  G.clear();

        cin >> boss;
        nodes[boss] = Node();
        for(int i = 1; i < n; i++) {
            cin >> son >> father;
            G[father].push_back(son);
            nodes[son] = Node();
        }

        if(dp(boss, 0) == dp(boss, 1)) {
            cout << dp(boss, 0) << " No" << endl;
        }
        else if(dp(boss, 0) > dp(boss, 1)) {
            if(nodes[boss].fhasSelect)
                cout << dp(boss, 0) << " No" << endl;
            else
                cout << dp(boss, 0) << " Yes" << endl;
        }
        else {
            if(nodes[boss].thasSelect)
                cout << dp(boss, 1) << " No" << endl;
            else
                cout << dp(boss, 1) << " Yes" << endl;
        }
    }

    return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值