大体题意:
给你n 个人的上司和下属的关系,让你挑尽可能多的人来参加聚会,参加聚会的条件是 任意两个人不能具有直接的上司下属的关系,求最大人数?
思路:
树形dp -- 树的最大独立集问题:
只不过多了一个条件,问是否唯一:
解法很容易想到了:
令dp[i][0]表示 第i 个人 如果不选择的话,最大人数, 令f[i][0] 为第i 个人不选择的话,解是否唯一。
同样的 令dp[i][1]为第i 个人选择的话,最大的人数,令f[i][1] 表示第i 个人选择的话,解是否唯一。
那么直接建图从1号老板开始dfs,在回溯的过程中进行状态转移。
转移dp[i][0]时,因为第i个人不选择,那么他的儿子结点 都可以要或者不要 max{dp[v][0],dp[v][1]}在说说f的转移
如果dp[v][0] == dp[v][1] 解肯定不唯一, 否则谁大,就判断谁的f!两边取个交集即可!
同样的,转移dp[i][1]时,因为第i 个人选择,那么他的儿子结点都不要,只能取dp[v][0],只判断 f[v][0]就好了!
详细见代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <map>
#include <string>
#include <vector>
#include <iostream>
using namespace std;
const int maxn = 200 + 7;
map<string,int>mp;
vector<int>g[maxn];
int id, n;
int dp[maxn][2],f[maxn][2];
char s[maxn],son[maxn];
int ID(string s){
if (!mp.count(s)){
return mp[s] = ++id;
}
return mp[s];
}
void init(){
id = 0;
for (int i = 0; i < maxn; ++i) g[i].clear();
mp.clear();
}
void dfs(int k){
int len = g[k].size();
if (!len){
dp[k][0] = 0; dp[k][1] = 1;
f[k][0] = 1; f[k][1] = 1;
return ;
}
dp[k][0] = 0;
dp[k][1] = 1;
f[k][0] = f[k][1] = 1;
for (int i = 0; i < len; ++i){
int v = g[k][i];
dfs(v);
if (dp[v][0] == dp[v][1]){
dp[k][0] += dp[v][0];
f[k][0] = 0;
}
else if (dp[v][0] > dp[v][1]){
dp[k][0] += dp[v][0];
f[k][0] = (f[k][0] && f[v][0]);
}
else {
dp[k][0] += dp[v][1];
f[k][0] = (f[k][0] && f[v][1]);
}
dp[k][1] += dp[v][0];
f[k][1] = (f[k][1] && f[v][0]);
}
}
int main(){
while(~scanf("%d",&n) && n){
scanf("%s",s);
init();
ID(s);
for (int i= 0 ; i < n-1; ++i){
scanf("%s%s",s,son);
g[ID(son)].push_back(ID(s));
}
dfs(1);
if (dp[1][1] > dp[1][0]) {
printf("%d ",dp[1][1]);
if (f[1][1])puts("Yes");
else puts("No");
}
else if (dp[1][1] < dp[1][0]){
printf("%d ",dp[1][0]);
if (f[1][0])puts("Yes");
else puts("No");
}
else {
printf("%d No\n",dp[1][1]);
}
}
return 0;
}