POJ - 3342 Party at Hali-Bula 树形DP

题目大意:某公司有个聚会,要邀请员工来参加。要求员工和他的直系上司不能同时到这个聚会,问最多能邀请到多少人,有多种邀请方法时输出No

解题思路:用dp[i][1]表示邀请第i个人,dp[i][0]表示没有邀请第i个人

初始dp[i][1] = 1, dp[i][0] = 0

状态转移方程为

dp[i][1] = sum(dp[son][0]) son为i的下属

dp[i][0] = sum(max(dp[son][1],dp[son][0])),上司不去,下属不一定要去

判断是否有多种邀请方法,只要往回回溯就可以

因为只有dp[i][0]这种状态会出现两个值选最大值的情况,所以只要判断这种状态下,dp[son][0] 会不会等于dp[son][1]就可以了

如果相等了,就有多种邀请方式了

#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
#include<map>
#include<string>
#include<iostream>
#include<queue>
#define maxn 210
using namespace std;
int n, cnt, dp[maxn][2];
vector<int> tree[maxn];
map<string,int> Map;
struct Node{
    int num, statu;
    Node() {}
    Node(int n, int s) {
        num = n;
        statu = s;
    }
};

void init() {
    Map.clear();
    cnt = 1;
    for(int i = 0; i <= n; i++)
        tree[i].clear();
    string str1, str2;
    cin >> str1;
    Map[str1] = cnt++;
    int x, y;
    for(int i = 0; i < n - 1; i++) {
        cin >> str1 >> str2;
        if(!Map[str1])
            Map[str1] = cnt++;
        if(!Map[str2])
            Map[str2] = cnt++;
        x = Map[str1];
        y = Map[str2];

        tree[y].push_back(x);
    }
}

void solve(int cur) {
    int size = tree[cur].size();
    dp[cur][1] = 1;
    dp[cur][0] = 0;
    for(int i = 0; i < size; i++) {
        solve(tree[cur][i]);
        dp[cur][1] += dp[tree[cur][i]][0];
        dp[cur][0] += max(dp[tree[cur][i]][0], dp[tree[cur][i]][1]);
    }
}

int main (){
    while(cin >> n) {
        if(!n)
            break;
        init();
        solve(1);
        queue<Node> q;
        if(dp[1][0] == dp[1][1])
            printf("%d No\n",dp[1][1]);
        else {
            if(dp[1][0] < dp[1][1]) {
                q.push(Node(1,1));
            }
            else
                q.push(Node(1,0));
            bool flag = false;
            while(!q.empty()) {
                Node t = q.front();
                q.pop();
                int s = t.statu, Num = t.num;
                int size = tree[Num].size();
                for(int i = 0; i < size; i++) {
                    if(s == 1)
                        q.push(Node(tree[Num][i],0));
                    else {
                        if(dp[tree[Num][i]][0] == dp[tree[Num][i]][1]) {
                            flag = true;
                            break;
                        }
                        else if(dp[tree[Num][i]][0] > dp[tree[Num][i]][1])
                            q.push(Node(tree[Num][i],0));
                        else
                            q.push(Node(tree[Num][i],1));
                    }
                }
                if(flag)
                    break;
            }
            if(flag)
                printf("%d No\n",max(dp[1][0],dp[1][1]));
            else
                printf("%d Yes\n", max(dp[1][0],dp[1][1]));
        }
    }
    return 0;
}
时间: 2024-12-16 11:41:56

POJ - 3342 Party at Hali-Bula 树形DP的相关文章

poj 1655 and 3107 and 2378 树形dp(树的重心问题)

简单的树形dp,顺便学习了树的重心的概念,即以该点为根的树的最大子树的结点数最少. poj 1655: 1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 using namespace std; 5 6 const int N = 20001; 7 int head[N]; 8 int balance[N]; 9 int child[N]; 10 int n, e; 11 12 struct

POJ 2342 &amp;&amp;HDU 1520 Anniversary party 树形DP 水题

一个公司的职员是分级制度的,所有员工刚好是一个树形结构,现在公司要举办一个聚会,邀请部分职员来参加. 要求: 1.为了聚会有趣,若邀请了一个职员,则该职员的直接上级(即父节点)和直接下级(即儿子节点)都不能被邀请 2.每一个员工都有一个兴奋值,在满足1的条件下,要使得邀请来的员工的兴奋值最高 输出最高的兴奋值. 简单的树形DP dp[i][1]:表示以i为根的子树,邀请节点i的最大兴奋值 dp[i][0]:表示以i为根的子树,不邀请节点i的最大兴奋值 先根据入度找出整棵树的根节点, 然后一次DF

POJ 3398 / UVA 1218 Perfect Service 树形DP

树形DP Perfect Service Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 1378   Accepted: 668 Description A network is composed of N computers connected by N ? 1 communication links such that any two computers can be communicated via a uniqu

POJ 2057 The Lost House 经典树形DP+贪心

题意:链接 方法:树形DP+贪心 解析:这是一道好题. 好首先要明确这题求的是什么? 名义上是期望值,而实际上就是找一条路径.什么路径呢?从根节点走遍所有的叶子节点所花费步数最短的路径. 明确了题意后该怎么做呢? 首先看我们需要什么? 目前有个根节点,我们需要知道从他向一个分支走,失败步数是多少,成功步数是多少? 那么怎么维护我们需要的东西呢? 首先我们先给他们起个名:suc,fai; 其次再给一个节点的叶子节点的个数起个名:son 起名完事之后我们就要更新了. 先谈叶子节点,显然叶子节点的su

poj 1694 An Old Stone Game 树形dp

//poj 1694 //sep9 #include <iostream> #include <algorithm> using namespace std; const int maxN=256; int n; int tree[maxN][maxN]; int ans[maxN]; int cmp(int a,int b) { return a>b; } int dfs(int u) { int tmp[maxN],t=0; if(tree[u][0]==0) retur

POJ题目1947 Rebuilding Roads(树形dp)

Rebuilding Roads Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 9957   Accepted: 4537 Description The cows have reconstructed Farmer John's farm, with its N barns (1 <= N <= 150, number 1..N) after the terrible earthquake last May. The

poj 2342 【Anniversary party】树形dp

题目传送门//res tp poj 题意 给出一棵有权树,求一个节点集的权值和,满足集合内的任意两点不存在边 分析 每个点有选中与不选中两种状态,对于第\(i\)个点,记选中为\(sel_i\),不选中为\(insel_i\) 若某一节点选中,则其子节点都不能选中. 若某一节点不选中,则其子节点有两种选择:1.选中 2.不选中 故 \[sel_i = val_i +\sum_j insel_j\] \[insel_i = \sum_j max\{insel_j,sel_j\}\] 其中\(j\)

【Poj】 p2342 Anniversary party(树形DP第一道)

Anniversary party Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 5523   Accepted: 3169 Description There is going to be a party to celebrate the 80-th Anniversary of the Ural State University. The University has a hierarchical structure

POJ 1849 Two(树的直径--树形DP)(好题)

大致题意:在某个点派出两个点去遍历所有的边,花费为边的权值,求最少的花费 思路:这题关键好在这个模型和最长路模型之间的转换,可以转换得到,所有边遍历了两遍的总花费减去最长路的花费就是本题的答案,要思考,而且答案和派出时的起点无关 求最长路两遍dfs或bfs即可,从任意点bfs一遍找到最长路的一个终点,再从这个终点bfs找到起点 //1032K 79MS C++ 1455B #include<cstdio> #include<iostream> #include<cstring

poj 3342(树形dp)

题意:在一个公司中要举办一个聚会,每一个员工有一个奉献值.为了和谐规定直接上下级不能一起出席.让你找出奉献值之和最大为多少. 思路:dp[v][1]表示当前结点选,能获得的最大奉献值,dp[v][0]表示当前节点不选能获得的最大奉献值.状态转移: dp[v][0] = max(dp[v][0], ∑max(dp[x][1], dp[x][0]))x为直接儿子 dp[v][1] = max(dp[v][1], ∑dp[x][0] + vex[v]) 最后答案是max(dp[root][0], dp