题目大意:有1个大boss,n-1个员工,每个员工只有一个直接上司,一个领导可以有多个员工,现在举行一个聚会,有直接关系的人不会同时出现,问最多能请多少个人,情况是否唯一。
题目思路:树形动态规划,求最大独立集,
1.设 dp[i][0]和 dp[i][1] 分别不表示选择和选择 i 结点所能得到的最大独立集人数。
状态转移方程:
dp[ i ][ 0 ] = sum(dp[ j ][ 0 ] , dp[ j ][ 1 ]); ( j 是 i 的孩子结点 )
dp[ i ][ 1 ] = sum(dp[ j ][ 0 ]) ; ( j 是 i 的孩子结点 )
2.设 f[i][0] 和 f[i][1] 分别表示不选择和选择则 i 结点的唯一性,1表示不唯一 ,0 表示唯一
求法:
在求dp[ i ][ 0 ] = sum(dp[ j ][ 0 ] , dp[ j ][ 1 ]); ( j 是 i 的孩子结点 )时:
即:求不选择 i 结点的情况:(选择 j 或者不选都可以 ) 当 dp[ j ][ 0 ]大的时候,即不选择 j 结点,如果不选择 j 结点的情况不是唯一的,那么不选择 i 结点的情况也不是唯一的。同理dp[ j ][ 1 ]比较大的时候道理是一样的。
故有
if(dp[son][0] > dp[son][1]){dp[u][0] += dp[son][0];if(f[son][0]) f[u][0] = 1;}else if(dp[son][0] == dp[son][1]){ dp[u][0]+=dp[son][0];f[u][0] = 1;}else {dp[u][0] += dp[son][1];if(f[son][1]) f[u][0] =1;}
#include<cstdio>
#include<iostream>
#include<vector>
#include<string>
#include<cstring>
#include<map>
#define N 205
using namespace std;vector<int> sons[N]; //存放孩子结点
map<string,int> v; //读取数据
int dp[N][2]; //dp[i][1]:选择i结点的最大独立集 dp[i][0]:不选择i结点的最大独立集
int f[N][2]; //f[i][1] : 选择i结点的最大独立集是否唯一(1:不唯一 0:唯一) f[i][0] : void dfs(int u){if(sons[u].empty()){ //叶子结点 dp[u][0]=0; dp[u][1]=1;return ;}int size = sons[u].size();for(int i=0 ;i<size ;i++){int son = sons[u][i];dfs(son);//计算选择u结点 dp[u][1] += dp[son][0];if(f[son][0]) f[u][1] = 1;// 计算不选择u结点 if(dp[son][0] > dp[son][1]){dp[u][0] += dp[son][0];if(f[son][0]) f[u][0] = 1;}else if(dp[son][0] == dp[son][1]){ dp[u][0]+=dp[son][0];f[u][0] = 1;}else {dp[u][0] += dp[son][1];if(f[son][1]) f[u][0] =1;}}dp[u][1]++; //加上u结点本身
}
int n;int main(){while(scanf("%d",&n)&&n){memset(dp,0,sizeof(dp));memset(f,0,sizeof(f));int top = 1;string s1,s2;cin>>s1;v[s1] = top++;for(int i=1 ;i<n ;i++){cin>>s1>>s2;if(!v[s1]) v[s1] = top++;if(!v[s2]) v[s2] = top++;sons[v[s2]].push_back(v[s1]); }dfs(1);if(dp[1][1]==dp[1][0]){printf("%d No\n",dp[1][1]);} else if(dp[1][1]>dp[1][0]){printf("%d %s\n",dp[1][1],f[1][1] ? "No" : "Yes");}else{printf("%d %s\n",dp[1][0],f[1][0] ? "No" : "Yes");}v.clear();for(int i=1 ;i<=n ;i++){sons[i].clear();}} return 0;
}