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

来,一起去POJ参加你的专属AC party

Party at Hali-Bula

Time Limit: 2000MS Memory Limit: 65536K
Total Submissions: 7184 Accepted: 2531

Description

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

先说一下题意吧,就是有一个party,让你去邀请嘉宾来一起嗨皮,但是你邀请来的人中不能有直系的老板与员工关系,因为这种关系的人在一起会不愉快,其实间接型雇佣关系的人在一起矛盾一般会更大好吧。不管了,就按他说的来吧,也就是说父亲节点和子节点是不能同时选中的,刚做个一个类似的题,那个题是父亲节点和子节点可以同时出现的,也是到树形dp的入门题,推荐看一看→POJ1463 策略游戏(树形dp)From now on...的CSDN

先解决第一步输入吧,需要确定成员之间的关系,比较揍瞎的是这道题给你的是人的姓名,你还要转换成代号,然后建一个图来表示他们之间的关系,几周前图论的时候我还在用二维字符数组呢。。。这里用的是map来表示姓名与序号的映射,vector来表示从属关系,其实也可以用静态链表模拟的链式向前星,就是写起来有点麻烦。

再者就是状态转移方程,这道题的状态转移方程相对比较简单,因为老板来了员工就不回来,老板不来员工随便。
dp[fa][1]+=dp[son][0];//老板来了 员工就不来 
dp[fa][0]+=max(dp[son][0],dp[son][1]);//老板没来 员工随便 

本道题的难点来了,就是最后的那个判断方法是否唯一的思路,我用一个辅助数组bool select[fa][bool],来表示老板来或者不来的时候结果是否唯一,这个特殊条件的判定就需要比较深奥的脑回路了,反正我没全部想出来,只能看了看大佬们的blogs,才给凑全

if(dp[son][0]==dp[son][1])
	select[fa][0]=0;//员工来不来都一样,so老板不来 结果不唯一 
if(select[son][0]==0)
	select[fa][1]=0;//员工不来都不唯一,老板来了又有什么用

最后就是输出时候的边界判定了,要说的都在我那乱七八糟的代码里,希望不要看烦了 ^_^

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#define ll long long
using namespace std;
const int inf=0x3f3f3f3f;
const int mm=205;
int dp[mm][2];//dp[i][0]表示不请i时的人数,else。。。 
int book[mm];//标记是否尝试过 
int select[mm][2];//标记是否唯一 
int n;
string bbos,bos,emp;//big boss,boss,emplyee 
map<string,int>mp;//名字与序号的映射 
vector<int>vt[mm];//从属关系 

void init(){
	mp.clear();
	for(int i=0;i<mm;i++)
		vt[i].clear();
	memset(book,0,sizeof(book));
	memset(dp,0,sizeof(dp));
}

void dfs(int fa){
	dp[fa][1]=1;
	book[fa]=1;
	select[fa][1]=1;
	select[fa][0]=1;//不妨设为 1,找矛盾的时候 
	int sz=vt[fa].size();//fa管理的员工数 
	for(int i=0;i<sz;i++){
		int son=vt[fa][i];//枚举员工
		if(book[son]==0){
			dfs(son);
			dp[fa][1]+=dp[son][0];//老板来了 员工就不来 
			dp[fa][0]+=max(dp[son][0],dp[son][1]);//老板没来 员工随便 
			if(dp[son][0]==dp[son][1])
				select[fa][0]=0;//员工来不来都一样,so老板不来 结果不唯一 
			if(select[son][0]==0)
				select[fa][1]=0;//员工不来都不唯一,老板来了又有什么用?!!!有点迷糊 
		}
	}
}

int main()
{
	while(~scanf("%d",&n)&&n){
		init();//忘了就WA了  
		int cnt=0;//出现过的所有人编号 
		cin>>bbos;
		mp[bbos]=cnt++;
		
		for(int i=0;i<n-1;i++){
			cin>>emp>>bos;
			if(!mp.count(emp))//没出现过  加入 
				mp[emp]=cnt++;
			if(!mp.count(bos))
				mp[bos]=cnt++;
				
			vt[mp[bos]].push_back(mp[emp]);//boss contral emp
		}
		dfs(0);
		//注意输出的判定 
		if(dp[0][1]>dp[0][0]&&select[0][1])
			printf("%d Yes\n",dp[0][1]);
		else if(dp[0][1]<dp[0][0]&&select[0][0])
			printf("%d Yes\n",dp[0][0]);
		else 
			printf("%d No\n",max(dp[0][0],dp[0][1]));
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值