题目链接:https://vjudge.net/problem/UVA-1220
题目描述:某人举办宴会请客,对于直属上下级关系的人不会同时请,除了大Boss外其他人都仅有一个直属上司,问最多能请多少人,所请的人是否唯一。
思路:训练赛时看了一眼这道题感觉dfs应该能过,但是跑去做另一道眼熟的题目去了,结果那道题也没做出来,这道题最后也没时间做了。赛后补题果然发现这道题更好做,第好几次判题失误了,宛若一个智障。对于每个节点分选或不选两种方式进行dfs即可,若选节点x,则其所有儿子节点都不能选,若不选x,则其所有儿子结点都可以选或不选,最终取最大值即可。对于判断最大数量下请的人是否唯一,用数组f[i][j]表示,j为0时表示不选i结果是否唯一,j为1时表示选i时结果是否唯一。最后用记忆化搜索保存每次的结果。设dp[i[[j]为选(j为1)或不选(j为0)i时能请的最大人数。按照上面的想法,若选i,则dp[i][j] += dp[child][0];若不选i,则dp[i][j] += max(dp[child][1],dp[child][0])。
代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<cstdlib>
#include<sstream>
#include<deque>
#include<stack>
#include<set>
#include<map>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const double eps = 1e-6;
const int maxn = 400 + 10;
const int mod = 10;
const int dx[] = {1, -1, 0, 0};
const int dy[] = {0, 0, -1, 1};
const int Dis[] = {-1, 1, -5, 5};
const int inf = 0x3f3f3f3f;
int n, m, k;
map<string, int> name;
vector<int> vec[maxn];
int dp[maxn][2], f[maxn][2];
int dfs(int x, int ff){//ff为0则表示不选结点x,为1则表示选
if(dp[x][ff]) return dp[x][ff];
int len = vec[x].size();
if(!len){//叶子结点
return dp[x][ff] = ff;
}
if(ff){//选结点x,则它的所有儿子结点都不能选
dp[x][ff] = 1;
for(int i = 0; i < len; ++i){
dp[x][ff] += dfs(vec[x][i], 0);
if(f[vec[x][i]][0]) f[x][ff] = 1;//如果不选儿子结点得到的答案不唯一,则选结点x得到的答案也不唯一
}
}
else{//不选结点x,则它的任意儿子结点都可以选,或者不选,二者取较大者
dp[x][ff] = 0;
int a, b;
for(int i = 0; i < len; ++i){
a = dfs(vec[x][i], 0); b = dfs(vec[x][i], 1);
dp[x][ff] += max(a, b);
if(a == b) f[x][ff] = 1;
else if(a > b && f[vec[x][i]][0]) f[x][ff] = 1;//如果选择的那种情况答案不唯一,则不选结点x的答案也不唯一
else if(b > a && f[vec[x][i]][1]) f[x][ff] = 1;
}
}
return dp[x][ff];
}
int main(){
string str1, str2;
while(~scanf("%d", &n) && n){
for(int i = 0; i < maxn; ++i) vec[i].clear();
name.clear();
memset(dp, 0, sizeof dp);
memset(f, 0, sizeof f);
int cnt = 0;
cin >> str1;
name[str1] = cnt++;
--n;
int u, v;
for(int i = 0; i < n; ++i){
cin >> str1 >> str2;
if(!name.count(str1)) name[str1] = cnt++;//为每一个名字赋编号
if(!name.count(str2)) name[str2] = cnt++;
u = name[str1], v = name[str2];
vec[v].push_back(u);
}
int cnt1 = dfs(0, 0), cnt2 = dfs(0, 1);//选根节点或不选根节点两种总的情况进行比较
if(cnt1 == cnt2){
printf("%d No\n", cnt1);
}
else if(cnt1 > cnt2){
printf("%d ", cnt1);
printf("%s\n", f[0][0] == 1 ? "No" : "Yes");
}
else{
printf("%d ", cnt2);
printf("%s\n", f[0][1] == 1 ? "No" : "Yes");
}
}
return 0;
}
/*
6
Jason
Jack Jason
Joe Jack
Jill Jason
John Jack
Jim Jill
2
Ming
Cho Ming
0
*/