hdu - 2412 - Party at Hali-Bula(树形dp)

题意:一棵n个结点的有根树(1 <= n <= 200),问最多能找出多少个结点使得找出的结点中任意两个结点没有直接相连的父子关系,并判断这个最大值方案是否唯一。

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2412

——>>状态:

dp[i][1]表示以结点 i 为根的子树,且选择i,能找出的满足要求的最大结点数。

dp[i][0]表示以结点 i 为根的子树,且不选择i,能找出的满足要求的最大结点数。

状态转移方程(结点 j 是结点 i 的儿子):

dp[i][1] += dp[j][0];

dp[i][0] += max(dp[j][1], dp[j][0]);

状态:

bUnique[i][1]表示以结点 i 为根的子树,且选择i,找出的满足要求的最大结点数的方案是否唯一。

bUnique[i][0]表示以结点 i 为根的子树,且不选择i,找出的满足要求的最大结点数的方案是否唯一。

叶子结点很明显。。对于非叶结点:

初始化为真,即唯一。。那么,什么时候会不唯一呢?

以结点 i 为根的子树,若选择i,那么其儿子不能选,所以儿子都是dp[j][0],只要其中一个dp[j][0]不唯一,dp[i][1]就不唯一。

以结点 i 为根的子树,若不选择i,那么对于其儿子,可选可不选,对于其中的一个儿子,如果dp[j][1] == dp[j][0],这时选哪个都行,dp[i][0]不唯一;如果dp[j][1] > dp[j][0],肯定选择了 j 这个儿子,如果bUnique[j][1] == false,那么dp[i][0]不唯一;如果dp[j][1] < dp[j][0],肯定不选择 j 这个儿子,如果bUnique[j][0] == false,那么dp[i][0]不唯一.。。

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

using std::max;
using std::cin;
using std::map;
using std::string;

const int MAXN = 200 + 1;

struct EDGE
{
    int nTo;
    int nNext;
};

int n;
int nHead[MAXN];
int nEdge;
int dp[MAXN][2];
bool bUnique[MAXN][2];
EDGE edge[MAXN << 1];

void Init()
{
    nEdge = 0;
    memset(nHead, -1, sizeof(nHead));
}

void AddEdge(int nFront, int nTo)
{
    edge[nEdge].nTo = nTo;
    edge[nEdge].nNext = nHead[nFront];
    nHead[nFront] = nEdge++;
}

void Read()
{
    int nCnt = 0;
    string strEmployee;
    string strBoss;
    map<string, int> mpName;

    cin >> strBoss;
    mpName[strBoss] = ++nCnt;
    for (int i = 2; i <= n; ++i)
    {
        cin >> strEmployee >> strBoss;
        if (mpName.find(strEmployee) == mpName.end())
        {
            mpName[strEmployee] = ++nCnt;
        }
        if (mpName.find(strBoss) == mpName.end())
        {
            mpName[strBoss] = ++nCnt;
        }
        AddEdge(mpName[strBoss], mpName[strEmployee]);
    }
}

void Dfs(int i)
{
    dp[i][1] = 1;
    dp[i][0] = 0;
    bUnique[i][1] = bUnique[i][0] = true;

    if (nHead[i] == -1)
    {
        return;
    }

    for (int e = nHead[i]; e != -1; e = edge[e].nNext)
    {
        int j = edge[e].nTo;
        Dfs(j);
        dp[i][1] += dp[j][0];
        dp[i][0] += max(dp[j][1], dp[j][0]);
    }
    for (int e = nHead[i]; e != -1; e = edge[e].nNext)
    {
        int j = edge[e].nTo;
        if (bUnique[j][0] == false)
        {
            bUnique[i][1] = false;
        }
        if ((dp[j][1] == dp[j][0]) ||
            (dp[j][1] > dp[j][0] && bUnique[j][1] == false) ||
            (dp[j][1] < dp[j][0] && bUnique[j][0] == false))
        {
            bUnique[i][0] = false;
        }
    }
}

void Output()
{
    if (dp[1][0] == dp[1][1])
    {
        printf("%d No\n", dp[1][0]);
    }
    else if (dp[1][0] > dp[1][1])
    {
        printf("%d ", dp[1][0]);
        bUnique[1][0] ? puts("Yes") : puts("No");
    }
    else
    {
        printf("%d ", dp[1][1]);
        bUnique[1][1] ? puts("Yes") : puts("No");
    }
}

int main()
{
    while (scanf("%d", &n) == 1 && n)
    {
        Init();
        Read();
        Dfs(1);
        Output();
    }

    return 0;
}
时间: 2024-08-29 00:42:56

hdu - 2412 - Party at Hali-Bula(树形dp)的相关文章

hdu 1561The more, The Better(树形dp&amp;01背包)

The more, The Better Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 4949    Accepted Submission(s): 2918 Problem Description ACboy很喜欢玩一种战略游戏,在一个地图上,有N座城堡,每座城堡都有一定的宝物,在每次游戏中ACboy允许攻克M个城堡并获得里面的宝

HDU 4008 Parent and son LCA+树形dp

题意: 给定case数 给定n个点的树,m个询问 下面n-1行给出树边 m个询问 x y 问:以x为根,y子树下 y的最小点标的儿子节点 和子孙节点 思路: 用son[u][0] 表示u的最小儿子 son[u][2] 表示u的次小儿子 son[u][1] 表示u的最小子孙 若lca(x,y)  !=y  则就是上述的答案 若lca(x,y) == y 1.y != 1 那么最小儿子就是除了x外的节点,且此时father[y] 也是y的儿子节点, 而最小的子孙节点就是1 2.y==1 那么特殊处理

HDU 4274 Spy&#39;s Work (树形DP,模拟)

题意: 给定一棵树,每个节点代表一个员工,节点编号小的级别就小,那么点1就是boss了.接下来给出对m个点的限制,有3种符号分别是op=“大于/小于/等于”,表示以第i个点为根的子树所有人的工资之和 大于/小于/等于 x,要求判断m个限制是否冲突了.注意每个员工的工资下限是1,而无上限.ps:可能出现对同个点多个限制,注意取交集. 思路: 很水的题嘛,想复杂了.注意限制是针对整棵子树的!所以我们只需要算出这棵子树的范围,再判断是否和所给的限制有冲突,如果没有冲突的话还得取“所给限制”与“计算出的

hdu 1011 Starship Troopers (依赖背包 树形dp)

题目: 链接:点击打开链接 题意: n个房间组成一棵树,你有m个战队,从1号房间开始依次clear每个房间,在每个房间需要花费的战队个数是bugs/20,得到的价值是the possibility of capturing a brain,求最大的价值. 算法: 树形dp,有依赖的背包问题.(依次clear每个房间) 思路: 状态转移dp[i][j]表示根结点为i时(房间i)花费j个战队能够得到的最大价值(捕捉到一个brain最大的可能值).递归求出每个根结点处的最大值,最后dp[1][m]就是

HDU 1561The more, The Better(树形DP)

HDU 1561  The more, The Better 题目大意就不说了 直接DP[i][j]表示i为跟节点的子树上攻克j个城堡的所能获得的最多宝物的数量 DP[fa][j] = MAX{DP[fa][i-k] + DP[child][k]}; 首先一个问题就是说如果子树u下的任意子节点被选择了,那么u是一定需要选择的,怎么在DP时保证准确性,其实这个很好解决,我们在计算时是需要枚举k(子节点的攻克数量)的,那么我们迫使k<j就可以了,这样的话DP[fa][j] 就不会被子节点的DP[ch

hdu 4003 Find Metal Mineral 【树形dp,分组背包】

题目:hdu 4003 Find Metal Mineral 题意:火星上发现了一些n个矿厂,有 k 个机器人从 s 点出发采矿,给出路段间的花费cost,求最小的花费采所有的矿. 分类:树形dp + 分组背包 分析:结论1:假如我们从 i点出发k个机器人采完以 k 为根节点的所有矿又回到 i 点,那么花费为 i 为根节点的cost 的和 乘以 k. 对于每个节点,定义状态:dp[i][j] 用 j 个机器人去采以 i 为根节点的子树的所有矿石的最小花费 状态转移方程:dp[father][nu

HDU 6201 2017沈阳网络赛 树形DP或者SPFA最长路

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6201 题意:给出一棵树,每个点有一个权值,代表商品的售价,树上每一条边上也有一个权值,代表从这条边经过所需要的花费.现在需要你在树上选择两个点,一个作为买入商品的点,一个作为卖出商品的点,当然需要考虑从买入点到卖出点经过边的花费.使得收益最大.允许买入点和卖出点重合,即收益最小值为0. 解法:我们设1为根节点,假设一开始一个人身上的钱为0.我们设dp[i][0]表示从根节点走到i及其子树并中任一点买

HDU 3586 Information Disturbing(二分+树形dp)

http://acm.split.hdu.edu.cn/showproblem.php?pid=3586 题意: 给定一个带权无向树,要切断所有叶子节点和1号节点(总根)的联系,每次切断边的费用不能超过上限limit,问在保证总费用<=m下的最小的limit. 思路: 对于上限limit我们可以二分查找.然后就是树形dp,看代码就可以理解的. 1 #include<iostream> 2 #include<algorithm> 3 #include<cstring>

HDU 4679:Terrorist’s destroy 树形DP

Terrorist’s destroy 题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=4679 题意: 给出一棵树,删除该树的某一条边会得到一个值a(该边的energy值)和一个值b(删除该边得到的两棵子树上的最大路径),求删除哪条边可以使得a*b最小,若存在多个最小值,则选择边号较小的那条. 树上所有相邻节点间的距离都为1. 题解: 可以知道删除某边后两棵子树的最长路径都是由原树直径的两个端点出发的,以任意一个节点为起点跑一边BFS(或者DFS