树形dp,相当于求最大独立子集!!!麻烦在于判断唯一性!!!
#include<iostream>
#include<stdio.h>
#include<map>
#include<vector>
#include<string>
using namespace std;
int n;
vector<int> son[205];
int dp[205][2];
int num;
int treep(int k,int p)//k为节点标号;p为是否选的标志
{//记忆化搜索
int i,len,sum;
if(dp[k][p]!=-1)
{return dp[k][p];}//以被算过
len=son[k].size();
if(p){//k被选k的儿子全不能选
sum=1;
for(int i=0;i<len;i++) sum=sum+treep(son[k][i],0);
dp[k][p]=sum;
return sum;}
else{//k不选k的儿子可选课不选
sum=0;
for(int i=0;i<len;i++) sum+=max(treep(son[k][i],0),treep(son[k][i],1));
dp[k][p]=sum;
return sum;
}
}
int check(){
int i,j;//保证每一次选择都是唯一的!!!
for(i=1;i<=n;i++)if(dp[i][0]>=dp[i][1])//若不选i<选i的情况;对于i一定不会相同
{for(j=0;j<son[i].size();j++)
if(dp[son[i][j]][1]==dp[son[i][j]][0])
return 0;}
return 1;
}
int main(){
while(scanf("%d",&n)==1&&n){
string s1,s2;
int flag=1;
for(int i=1;i<=n;i++) son[i].clear();
for(int i=1;i<=n;i++) dp[i][0]=dp[i][1]=-1;//表示i点的dp值还没算过;
cin>>s1;
if(n==1) {cout<<"1 Yes"<<endl;continue;}
num=0;
map<string,int> m;
m.clear();
m[s1]=++num;//第一个节点编号为一
for(int i=1;i<n;i++){
cin>>s1>>s2;
if(!m[s1]) m[s1]=++num;
if(!m[s2]) m[s2]=++num;
son[m[s2]].push_back(m[s1]);//建立树;
}
for(int i=1;i<=n;i++)//节点最大编号为n
if(son[i].size()==0){//找道叶子节点!!!
dp[i][0]=0;dp[i][1]=1;}//被选则为1不选则为0;
int ans1=treep(1,0);
int ans2=treep(1,1);
cout<<max(ans1,ans2);
if(ans1==ans2) flag=0;
if(flag) flag=check();//判断是否唯一
if(flag)
cout<<" Yes"<<endl;
else
cout<<" No"<<endl;
}
return 0;}