当前位置: 代码迷 >> 综合 >> hdu - 2412 - Party at Hali-Bula(树形dp)
  详细解决方案

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

热度:98   发布时间:2024-01-10 12:57:56.0

题意:一棵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;
}