题目链接:https://cn.vjudge.net/problem/HDU-2412
题目大意
公司有n个人,每个人都有自己的直接上司。公司要举办舞会,邀请员工参加,但是每个员工都不想和直接上司一起参加,问最多可以邀请多少个人参加舞会,并且回答是不是只有唯一的邀请方案。
分析
树形dp模板题,dp[x][0]表示x不参加舞会的最优解,dp[x][1]表示x参加舞会的最优解。如果某个人x参加舞会,那么x的直接下属就不能参加;如果x不参加,那么x的直接下属可以参加,也可以不参加,那么就在两种情况里面取最大值。至于方案是否唯一,可以开一个is数组标记。第一种情况:上司x参加,下属 j 不参加,如果is[j][0]==0,那么is[x][1] = 0;第二种情况:上司不参加,如果下属参加与不参加人数相同,即dp[j][0] == dp[j][1],那么is[x][0] = 0。is数组初始化为1。
代码
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <map>
using namespace std;
const int N = 1510;
int n, cnt, head[N];
int dp[N][2];
bool is[N][2];
struct Edge {
int to, nxt;
}edge[N];
void add(int a, int b) {
edge[cnt].to = b;
edge[cnt].nxt = head[a];
head[a] = cnt++;
}
void dfs(int x) {
dp[x][1] = 1;
is[x][1] = 1;
is[x][0] = 1;
for(int i = head[x]; i != -1; i = edge[i].nxt) {
int j = edge[i].to;
dfs(j);
dp[x][0] += max(dp[j][0], dp[j][1]);
dp[x][1] += dp[j][0];
if(!is[j][0]) is[x][1] = 0;
if(dp[j][0] == dp[j][1]) is[x][0] = 0;
}
}
int main() {
while(~scanf("%d", &n),n) {
cnt = 0;
memset(head, -1, sizeof head);
map<string,int> mp;
string s,t;
int d = 1;
cin>>s;
mp[s] = d++;
for(int i = 1; i < n; i++) {
cin>>t>>s;
if(mp[s] == 0) mp[s] = d++;
if(mp[t] == 0) mp[t] = d++;
add(mp[s], mp[t]);
}
memset(is, 0, sizeof is);
memset(dp, 0, sizeof dp);
dfs(1);
if(dp[1][0] > dp[1][1] && is[1][0])
printf("%d Yes\n", dp[1][0]);
else if(dp[1][1] > dp[1][0] && is[1][1])
printf("%d Yes\n", dp[1][1]);
else
printf("%d No\n", max(dp[1][0], dp[1][1]));
}
return 0;
}