题干:

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[][0]或者dp[][1]这两个状态中的一个,所以你就想,,(假设父节点u子节点v)如果我当前节点用的是dp[u][1],那么对于子节点就制造不出矛盾,如果我用的是dp[u][0],那么我们就可以看子节点是否有矛盾(因为这时候子节点是可以选择的),如果我选和不选都可以取到max,那么矛盾就出来了。(有的同学会问,你这一个点取到max有啥用,万一我不取这一分支呢,但是其实是不存在这种顾虑的,因为你是dp啊,有更大的值肯定会选啊,,其实究其原因还是那句“最终的答案中一定每个顶点都用到了dp[][0]或者dp[][1]这两个状态中的一个”,,所以这俩状态哪个更大我肯定会取这个值,,(好吧其实还是用一个标记数组直接递推上去比较靠谱))

AC代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<map>
#include<vector>
#include<set>
#include<string>
#include<cmath>
#include<cstring>
#define ll long long
#define pb push_back
#define pm make_pair
#define fi first
#define se second
using namespace std;
const int MAX = 2e5 + 5;
map<string,int> mp;
vector<int >vv[505];
char s[205],s1[205],s2[205];
int dp[505][2];
int haha;
void dfs(int cur,int root) {
	dp[cur][1]=1;
	int up = vv[cur].size();
	for(int i = 0; i<up; i++) {
		int v = vv[cur][i];
		if(v == root) continue;
		dfs(v,cur);
		dp[cur][1] += dp[v][0];
		dp[cur][0] += max(dp[v][0],dp[v][1]);
	}
	for(int i = 0; i<up; i++) {
		int v = vv[cur][i];
		if(v == root) continue;
		if(dp[cur][0] > dp[cur][1] && dp[v][0] == dp[v][1]) haha=0;
	}
}
int main()
{
	int n,tot;
	while(~scanf("%d",&n)) {
		if(n == 0) break; 
		haha=1;
		mp.clear();
		for(int i = 1; i<=n; i++) vv[i].clear();
		memset(dp,0,sizeof dp);
		tot=0;
		scanf("%s",s);
		mp[s] = ++tot;
		for(int i = 1; i<=n-1; i++) {
			scanf("%s%s",s1,s2);
			if(mp.find(s1) == mp.end()) mp[s1] = ++tot;
			if(mp.find(s2) == mp.end()) mp[s2] = ++tot;
			int t1=mp[s1],t2=mp[s2];
			vv[t1].pb(t2);vv[t2].pb(t1);
		}
		dfs(1,0);
		printf("%d ",max(dp[1][0],dp[1][1]));
		if(dp[1][0] == dp[1][1]) haha=0;
		if(haha == 1) printf("Yes");
		else printf("No");
		printf("\n");
	}
	
	return 0 ;
 }

 

错误代码1:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<map>
#include<vector>
#include<set>
#include<string>
#include<cmath>
#include<cstring>
#define ll long long
#define pb push_back
#define pm make_pair
#define fi first
#define se second
using namespace std;
const int MAX = 2e5 + 5;
map<string,int> mp;
vector<int >vv[505];
char s[205],s1[205],s2[205];
int dp[505][2];
int qq[505];
int forbid;
void dfs(int cur,int root) {
	if(cur != forbid)dp[cur][1]=1;
	int up = vv[cur].size();
	for(int i = 0; i<up; i++) {
		int v = vv[cur][i];
		if(v == root) continue;
		dfs(v,cur);
		if(cur != forbid) dp[cur][1] += dp[v][0];
		dp[cur][0] += max(dp[v][0],dp[v][1]);
	}
}
int main()
{
	int n,tot;
	while(~scanf("%d",&n)) {
		if(n == 0) break; 
		forbid=-1;
		mp.clear();
		for(int i = 1; i<=n; i++) vv[i].clear();
		memset(dp,0,sizeof dp);
		memset(qq,0,sizeof qq);
		tot=0;
		scanf("%s",s);
		mp[s] = ++tot;
		for(int i = 1; i<=n-1; i++) {
			scanf("%s%s",s1,s2);
			if(mp.find(s1) == mp.end()) mp[s1] = ++tot;
			if(mp.find(s2) == mp.end()) mp[s2] = ++tot;
			int t1=mp[s1],t2=mp[s2];
			vv[t1].pb(t2);vv[t2].pb(t1);
		}
		dfs(1,0);
		printf("%d ",max(dp[1][0],dp[1][1]));
		int ans = max(dp[1][0],dp[1][1]);
		int cnt = 0;
		for(int i = 1; i<=n; i++) {
			forbid = i;
			if(max(dp[1][0],dp[1][1]) == ans) cnt++;
		}
		if(cnt == 1) printf("Yes");
		else printf("No");
		printf("\n");
	}
	
	return 0 ;
 }

错误代码2:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<map>
#include<vector>
#include<set>
#include<string>
#include<cmath>
#include<cstring>
#define ll long long
#define pb push_back
#define pm make_pair
#define fi first
#define se second
using namespace std;
const int MAX = 2e5 + 5;
map<string,int> mp;
vector<int >vv[505];
char s[205],s1[205],s2[205];
int dp[505][2];
int qq[505];
int haha;
void dfs(int cur,int root) {
	dp[cur][1]=1;
	int up = vv[cur].size();
	for(int i = 0; i<up; i++) {
		int v = vv[cur][i];
		if(v == root) continue;
		dfs(v,cur);
		dp[cur][1] += dp[v][0];
		dp[cur][0] += max(dp[v][0],dp[v][1]);
	}
}
void DFS(int cur,int root,int res) {
	if(res == 1) haha++;
	int up = vv[cur].size();
	for(int i = 0; i<up; i++) {
		int v = vv[cur][i];
		if(v == root) continue;
		if(max(dp[v][0],dp[v][1]) == res-1)
		DFS(v,cur,res-1);
	}
}
int main()
{
	int n,tot;
	while(~scanf("%d",&n)) {
		if(n == 0) break; 
		haha=0;
		mp.clear();
		for(int i = 1; i<=n; i++) vv[i].clear();
		memset(dp,0,sizeof dp);
		memset(qq,0,sizeof qq);
		tot=0;
		scanf("%s",s);
		mp[s] = ++tot;
		for(int i = 1; i<=n-1; i++) {
			scanf("%s%s",s1,s2);
			if(mp.find(s1) == mp.end()) mp[s1] = ++tot;
			if(mp.find(s2) == mp.end()) mp[s2] = ++tot;
			int t1=mp[s1],t2=mp[s2];
			vv[t1].pb(t2);vv[t2].pb(t1);
		}
		dfs(1,0);
		printf("%d ",max(dp[1][0],dp[1][1]));
		int ans = max(dp[1][0],dp[1][1]);
		DFS(1,0,ans);
//		int cnt = 0;
//		for(int i = 1; i<=n; i++) {
//			if(max(dp[1][0],dp[1][1]) == ans) cnt++;
//		}
//		//printf("%d",mp["Jill"]);
		if(haha == 1) printf("No");
		else printf("Yes");
		printf("\n");
	}
	
	return 0 ;
 }

错误代码3:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<map>
#include<vector>
#include<set>
#include<string>
#include<cmath>
#include<cstring>
#define ll long long
#define pb push_back
#define pm make_pair
#define fi first
#define se second
using namespace std;
const int MAX = 2e5 + 5;
map<string,int> mp;
vector<int >vv[505];
char s[205],s1[205],s2[205];
int dp[505][2];
int qq[505];
int haha;
void dfs(int cur,int root) {
	dp[cur][1]=1;
	int up = vv[cur].size();
	for(int i = 0; i<up; i++) {
		int v = vv[cur][i];
		if(v == root) continue;
		dfs(v,cur);
		dp[cur][1] += dp[v][0];
		dp[cur][0] += max(dp[v][0],dp[v][1]);
	}
}
void DFS(int cur,int root,int res,bool cho) {//cho==0代表当前点没选			//ok==0代表当前点不能选 
	if(res == 1) {
		haha++;return ;
	}
	int up = vv[cur].size();
	for(int i = 0; i<up; i++) {
		int v = vv[cur][i];
		if(v == root) continue;
		//if(max(dp[v][0],dp[v][1]) == res-1)
		if(cho == 1) {
			if(dp[v][0] == res-1) DFS(v,cur,res-1,0);
		}
		else {
			if(dp[v][0] == res-1) DFS(v,cur,res-1,0);
			if(dp[v][1] == res-1) DFS(v,cur,res-1,1);
		}
		
	}
}
int main()
{
	int n,tot;
	while(~scanf("%d",&n)) {
		if(n == 0) break; 
		haha=0;
		mp.clear();
		for(int i = 1; i<=n; i++) vv[i].clear();
		memset(dp,0,sizeof dp);
		memset(qq,0,sizeof qq);
		tot=0;
		scanf("%s",s);
		mp[s] = ++tot;
		for(int i = 1; i<=n-1; i++) {
			scanf("%s%s",s1,s2);
			if(mp.find(s1) == mp.end()) mp[s1] = ++tot;
			if(mp.find(s2) == mp.end()) mp[s2] = ++tot;
			int t1=mp[s1],t2=mp[s2];
			vv[t1].pb(t2);vv[t2].pb(t1);
		}
		dfs(1,0);
		printf("%d ",max(dp[1][0],dp[1][1]));
		int ans = max(dp[1][0],dp[1][1]);
		if(dp[1][1] == ans) {
			DFS(1,0,ans,1);
		}
		if(dp[1][0] == ans) {
			DFS(1,0,ans,0);
		}
//		DFS(1,0,ans);
//		int cnt = 0;
//		for(int i = 1; i<=n; i++) {
//			if(max(dp[1][0],dp[1][1]) == ans) cnt++;
//		}
//		//printf("%d",mp["Jill"]);
		if(haha == 1) printf("Yes");
		else printf("No");
		printf("\n");
	}
	
	return 0 ;
 }

用二维数组标记的dfs(Orzwjh大佬)

void dfs(int rt)
{
	for(int i=head[rt];i!=-1;i=side[i].nex)
	{
		int ty=side[i].v;
		dfs(ty);
		if(mk[ty][0]==1)
		{
			mk[rt][1]=1;
		}
		dp[rt][1]+=dp[ty][0];
		
		if(dp[ty][0]==dp[ty][1])
		{
			dp[rt][0]+=dp[ty][0];
			mk[rt][0]=1;
		}
		else if(dp[ty][0]>dp[ty][1])
		{
			dp[rt][0]+=dp[ty][0];
			if(mk[ty][0]==1)
			mk[rt][0]=1;
		}
		else
		{
			dp[rt][0]+=dp[ty][1];
			if(mk[ty][1]==1)
			mk[rt][0]=1;
		}
	}
}

总结 记住了一直都是用孩子节点的值去更新父亲节点的值就好了。