您的位置:首页 > 其它

HDU2412 & POJ3342 Party at Hali-Bula_树形DP

2014-02-19 15:31 441 查看
原题:


Party at Hali-Bula

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)

Total Submission(s): 1605 Accepted Submission(s): 544



Problem 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


Source

2006 Asia Regional Tehran

Recommend

lcy

题意:

一颗树上选尽量多的点组成一个点集,保证每个点与自己的父亲节点不同时在此点集中。

并判断这个最大点集的选法是否唯一。输出点集个数和选法的唯一性判断。

如果只是上面的找最大点集就是一道很水的DP,但是要判断唯一性就要加一点东西了。

首先是最大点集,

定义状态:dp【i】【0/1】分别表示选或不选第i个点,在以第i个点为根的子树中所能取得的最大点集

转移 dp[i][0]+=max(dp[son][0],dp[son][1]);//i结点不选,所以他的儿子都可选可不选,选较优的;

dp[i][1]+= dp[son][0];//i结点选了,那么他的儿子都不能选

沿树根做一遍DFS就可以获得结果。

判断唯一性: 做dfs的时候同时用一个标记数组 flag[i][0/1]来标记 当选或不选第i个结点的时候,第i个结点为根的子树中,该最大值的获取是否唯一 0表示唯一,大于0表示不唯一。

在做dfs的时候,flag[i][1]+=flag[son][0];

if(dp[son][0]==dp[son][1]) flag[i][0]=1;//表示如果当前的儿子结点的两个值相等的话,本身就产生了不唯一的方案

else if(dp[son][0]>dp[son][1]) flag[1][0]+=flag[son][0];//否则,选哪个,就把儿子结点对应状态的对应flag加上来就行了。

else flag[1][0]+=flag[son][1];

由于只需判断,不需要计算可能的方案个数,所以flag中的值只要大于0即可,不需要管是几

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>

using namespace std;

vector<int >T[250];

typedef struct mystruct{
char name[105];
}DATA;

DATA emp[250];
int n;
int flag[250];
int dp[250][3],yes_or_no[250][3];
int gg;
int gg_special_0;
int max_num;
int find_max(int a,int b)
{
return a>b?a:b;
}
void dfs(int u)
{
flag[u]=1;
dp[u][1]=1;
if (T[u].size()==0)return;//表明是叶子结点,那就选自己

int i,son;
for ( i = 0; i <T[u].size() ; i++)
{
son=T[u][i];
if (!flag[T[u][i]])
{
dfs(son);
}
dp[u][0]+= find_max(dp[son][0],dp[son][1]);
dp[u][1]+= dp[son][0];
yes_or_no[u][1]+=yes_or_no[son][0];
if (dp[son][0]==dp[son][1])yes_or_no[u][0]++;
else if(dp[son][0]>dp[son][1])yes_or_no[u][0]+=yes_or_no[son][0];
else yes_or_no[u][0]+=yes_or_no[son][1];
}
return ;
}
//void dfs_0(int u,int condition)
//{
//	int son;
//	if (condition==1)
//	{
//		for (int i = 0; i < T[u].size(); i++)
//		{
//			dfs_0(T[u][i],0);
//		}
//	}
//	else
//	{
//		for (int i = 0; i < T[u].size(); i++)
//		{
//			son=T[u][i];
//			if (dp[son][0]==dp[son][1])
//			{
//				gg=0;
//			}
//			else
//			{
//				if (dp[son][0]>dp[son][1])
//				{
//					dfs_0(son,0);
//				}
//				else
//				{
//					dfs_0(son,1);
//				}
//			}
//		}
//	}
//}
int main()
{
int i,j,k,employee,boss;
char temp[105];
while ( scanf("%d",&n),n!=0)
{
for ( i = 1; i <=n ; i++)
{
T[i].clear();
}
gg=1;
gg_special_0=1;
max_num=0;
memset(flag,0,sizeof(flag));
memset(dp,0,sizeof(dp));
memset(yes_or_no,0,sizeof(yes_or_no));
//建树
scanf("%s",emp[1].name);
k=2;
for ( i = 2; i <=n ; i++)
{
scanf("%s",temp);
for ( j = 1; j <k ; j++)
{
if (strcmp(temp,emp[j].name)==0)
{
break;
}
}
if (j==k)//表示员工还没有出现过
{
strcpy(emp[k].name,temp);
employee=k;
k++;
}
else
{
employee=j;
}
scanf("%s",temp);
for ( j = 1; j <k ; j++)
{
if (strcmp(temp,emp[j].name)==0)
{
break;
}
}
if (j==k)//表示老板还没有出现过
{
strcpy(emp[k].name,temp);
boss=k;
k++;
}
else
{
boss=j;
}
T[boss].push_back(employee);
}
T[0].push_back(1);
//dfs
dfs(1);
max_num=find_max(dp[1][1],dp[1][0]);
//dfs_0(0,0);
printf("%d ",max_num);
if(dp[1][1]==dp[1][0] || (dp[1][1]>dp[1][0] && yes_or_no[1][1]>0) || (dp[1][1]<dp[1][0] && yes_or_no[1][0]>0))printf("No\n");
else printf("Yes\n");
}

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: