POJ 3342- Party at Hali-Bula (树形dp+判断是否唯一)

题目:

Dear Contestant,

I'm going to have a party at my villa at Hali-Bula to celebrate my retirement from BCM. I wish I could invite all my co-workers, but imagine how an employee can enjoy a party when he finds his boss among the guests! So, I decide not to invite both an employee and his/her boss. The organizational hierarchy at BCM is such that nobody has more than one boss, and there is one and only one employee with no boss at all (the Big Boss)! Can I ask you to please write a program to determine the maximum number of guests so that no employee is invited when his/her boss is invited too? I've attached the list of employees and the organizational hierarchy of BCM.

Best,
--Brian Bennett

P.S. I would be very grateful if your program can indicate whether the list of people is uniquely determined if I choose to invite the maximum number of guests with that condition.

Input

The input consists of multiple test cases. Each test case is started with a line containing an integer n (1 ≤ n ≤ 200), the number of BCM employees. The next line contains the name of the Big Boss only. Each of the following n-1 lines contains the name of an employee together with the name of his/her boss. All names are strings of at least one and at most 100 letters and are separated by blanks. The last line of each test case contains a single 0.

Output

For each test case, write a single line containing a number indicating the maximum number of guests that can be invited according to the required condition, and a word Yes or No, depending on whether the list of guests is unique in that case.

Sample Input

6
Jason
Jack Jason
Joe Jack
Jill Jason
John Jack
Jim Jill
2
Ming
Cho Ming
0

Sample Output

4 Yes
1 No

题目大意:在一个公司中要举办一个聚会,每一个员工有一个奉献值。为了和谐规定直接上下级不能一起出席。

解题思路:很明显是树形dp,但是麻烦的是要判断方案是否唯一。首先你要知道我们的答案中一定每个顶点都用到了dp[][0](表示不选当前这个节点)或者dp[][1](表示选当前这个节点)这两个状态中的一个,所以你就想,,(假设父节点u子节点v)如果我当前节点用的是dp[u][1],那么对于子节点就制造不出矛盾,如果我用的是dp[u][0],那么我们就可以看子节点是否有矛盾(因为这时候子节点是可以选择的),如果我选和不选都可以取到max,那么矛盾就出来了。(有的同学会问,你这一个点取到max有啥用,万一我不取这一分支呢,但是其实是不存在这种顾虑的,因为你是dp啊,有更大的值肯定会选啊,,其实究其原因还是那句“最终的答案中一定每个顶点都用到了dp[][0]或者dp[][1]这两个状态中的一个”,,所以这俩状态哪个更大我肯定会取这个值,,(好吧其实还是用一个标记数组直接递推上去比较靠谱))

AC代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<map>
#include<set>
#include<stack>
#include<queue>
#include<vector>
#define ll long long
using namespace std;
int n;
const int INF=505;
int dp[INF][2];
int vis[INF];//标记所访问过的点,每个点只需访问一次 
int mp[INF][2];//mp[j][1]为1,表示选当前这个节点,方案唯一,反之则不唯一。
//mp[j][0]为1,表示不选这个节点时,方案唯一,反之则不唯一 
vector<int>v[INF];
void dfs(int x)
{
	dp[x][1]=1;
	mp[x][1]=1;
	mp[x][0]=1;
	vis[x]=1;
	int m=v[x].size() ;
	int i,j,k;
	for(i=0;i<m;i++)
	{
		j=v[x][i];
		if(vis[j]==0)
		{
			dfs(j);
			dp[x][0]+=max(dp[j][0],dp[j][1]);//父亲节点没选,子节点选不选均可,所以取两者较大者 
			dp[x][1]+=dp[j][0];//父亲节点选了,子节点不能再选 
			if(dp[j][0]==dp[j][1])//会造成方案不唯一 
			{
				mp[x][0]=0;
			}
			if(mp[j][0]==0)
			{
				mp[x][1]=0;
			}
		}
	}
}
int main()
{
	while(1)
	{
		scanf("%d",&n);
		if(n==0)break;
		int i,j,k,val;
		for(i=0;i<INF;i++)
		{
			v[i].clear() ;
		}
		string a1,a2;
		cin>>a1;
		map<string,int>q;
		int cnt=1;
		q[a1]=cnt++;
		for(i=1;i<n;i++)
		{
			cin>>a1>>a2;
			if(!q.count(a1) )
			{
				q[a1]=cnt++;
			}
			if(!q.count(a2) ){
				q[a2]=cnt++;
			}
			v[q[a2]].push_back(q[a1]); 
		}
		memset(dp,0,sizeof(dp));
		memset(vis,0,sizeof(vis));
		dfs(1);
		//注意只有两种情况下方案唯一 
		if(dp[1][0]>dp[1][1]&&mp[1][0]==1)
		{
			printf("%d Yes\n",dp[1][0]);
		}
		else if(dp[1][1]>dp[1][0]&&mp[1][1]==1)
		{
			printf("%d Yes\n",dp[1][1]);
		}
		else printf("%d No\n",max(dp[1][0],dp[1][1]));
	}
    return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值