您的位置:首页 > 其它

pku 3342 Party at Hali Bula 树形dp 解题报告

2009-10-24 13:40 435 查看
pku 3342_Party at Hali Bula解题报告.
题目链接:http://acm.pku.edu.cn/JudgeOnline/problem?id=3342
题意:有n个人参加party,其中每2个人可能是上司与下属的关系。规定上司参加,他的下属就不能参加;或者下属参加,他的上司就不参加。问最多可以有多少个人参加这个party,如果方法不唯一,输出No与人数,唯一输出Yes与人数。

思路:
1、很明显此题是应用树形dp的好题。关于解决树形dp的较好方法就是从低向上的dp方法。所以我们可以从最低的下属开始计算,并一层一层保存而且往上计算。最后输出最高层的答案。而每个人只有2种选择,参加或者不参加;最低层是可知的,那么往上一层则需要考虑到下一层,即孩子的两种情况。那么状态转移方程可推知:
ans[father][1] += ans[temp][0];
ans[father][0] += Max(ans[temp][0], ans[temp][1]);
2、另一个问题则需要考虑答案是否为唯一性。
我是这样想的,以父亲与孩子各一个来考虑,当父亲参加与不参加的结果是一样的话,假设为1与1,而孩子参加与不参加的结果也是一样,假设也为0与0,那么一共可以选择的是4条子树,而每条子树的总结果都为1+0=1,也就说答案不唯一。同理考虑,父亲参加与不参加的结果不一样,即1与0,孩子的一样,即0与0;或者父亲一样,即1与1,孩子的不一样,即0与0;也或者两者都不一样,都为1与0。那么答案是唯一的,因为每种情况中,总是有一条子树是最大的。所以判断其唯一性:
if (ans[father][0] == ans[father][1] && ans[temp][0] == ans[temp][1])
{
flag = 0;
}
3、由于是用到树形dp,所以考虑dfs。

代码如下:
#include <stdio.h>
#include <string.h>
#define Max(a, b) (a > b ? a : b)

int son[205][205], unique[205][2], ans[205][2], last, flag;
char name[205][205];

int get_id(char str[])
{
int i;
for (i = 0; i < last; i++)
{
if(strcmp(name[i],str) ==0)
{
return i;
}
}
//从来没有出现过就存储在name中
if (i == last)
{
strcpy(name[i], str);
last++;
return i;
}
return 0;
}

void dfs(int father)
{
int i, sum, temp;

sum = son[father][0];
for (i = 1; i <= sum; i++)
{
temp = son[father][i];
dfs(temp);
//状态转移方程
ans[father][1] += ans[temp][0];
ans[father][0] += Max(ans[temp][0], ans[temp][1]);
//唯一性的考虑
if (ans[father][0] == ans[father][1] && ans[temp][0] == ans[temp][1])
{
flag = 0;
}
}
}

int main()
{
freopen("1.txt", "r", stdin);
int i, n, a, b;
char str[105], eme[105], boss[105];

while (scanf("%d", &n)&&n)
{
last = 0;
flag = 1;
for (i = 0; i < n; i++)
{
ans[i][1] = 1;
ans[i][0] = 0;
}
memset(son, 0, sizeof(son));
memset(name, '/0', sizeof(name));
memset(unique, 1, sizeof(unique));
scanf("%s", str);
get_id(str);
//用son保存数据,即用到链表的形式。
for (i = 1; i < n; i++)
{
scanf("%s%s", eme, boss);
a = get_id(eme);
b = get_id(boss);
son[b][++son[b][0]] = a;
}
dfs(0);
if (ans[0][0] > ans[0][1])
{
printf("%d %s/n", ans[0][0], flag ? "Yes" : "No");
}
else if (ans[0][0] < ans[0][1])
{
printf("%d %s/n", ans[0][1], flag ? "Yes" : "No");
}
else
{
printf("%d No/n", ans[0][0]);
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: