相比POJ 2342那题,增加了一问:最佳选择是否唯一的.
首先可根据雇员与老板的关系建立一颗树,老板做根节点,雇员是该根节点的儿子。
如上面这棵简易的树,对于节点A有两种决策: 选与不选。 若选择A,则B 、C都不能选,问题转换为求所有以 “B、C的儿子为根节点的树” 子问题最优解之和。 若不选A, 则问题转换为求“以B、C为根节点"的子树的最优解之和。
写成状态方程就是: d[ i ] = max { sigma ( d[ i 的儿子 ] ) , sigma ( d[ i 的孙子 ] ) + 1 } d [ i ] 表示以 i 为根节点的树的最优解。
讲这个过程写成递归的函数就能得到答案。
类似的,可以递归地去判断最优解是否唯一, 在所有的做过的决策中,只要有一个 ”sigma ( d[ i 的儿子 ] ) == sigma ( d[ i 的孙子 ] ) + 1 “ 答案就不是唯一的。
#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <algorithm>
#include <vector>
#include <map>
using namespace std;
const int MAXN=200+10;
vector<int>tree[MAXN];
map<string,int>mp;
int son[MAXN],gson[MAXN];
int num,N;
int Read_StoI()
{
char tmp[105];
scanf("%s",tmp);
string s=tmp;
if(mp.find(s)==mp.end()) mp[s]=++num;
return mp[s];
}
void DFS(int x)
{
son[x]=0,gson[x]=1;
int i,m=tree[x].size();
for(i=0;i<m;i++)
{
int p=tree[x][i];
DFS(p);
son[x] += max(son[p] , gson[p]);
gson[x] += son[p];
}
}
bool is_unique(int x)
{
if(son[x] == gson[x]) return false;
int i,m=tree[x].size();
if(son[x] > gson[x])
{
for(i=0;i<m;i++)
{
if(!is_unique(tree[x][i])) return false;
}
}
else
{
for(i=0;i<m;i++)
{
int Son=tree[x][i],j,SonNum=tree[Son].size();
for(j=0;j<SonNum;j++)
{
if(!is_unique(tree[Son][j])) return false;
}
}
}
return true;
}
int main()
{
while(scanf("%d",&N),N)
{
num=0;
mp.clear();
for(int i=0;i<=N;i++) tree[i].clear();
Read_StoI();
for(int i=1;i<N;i++)
{
int employee=Read_StoI(),boss=Read_StoI();
tree[boss].push_back(employee);
}
DFS(1);
int MaxNumOfGuest=max(son[1],gson[1]);
printf("%d %s\n",MaxNumOfGuest,is_unique(1) ? "Yes" : "No" );
}
return 0;
}
当然,上面的代码可以改进,求最多人数和判断是否唯一可以结合在一起。