好久没有写解题报告了,这次把上个月做的一些题都写写,上个月做了不少的树形DP,先从这个比较简单的入手。
这个题目与hdu 1520 Anniversary party那道很裸的树形DP差不多,只不过这道题不仅要求出最多的人,还要判断是不是唯一。主要是如何判断人数是不是唯一的。出现多解的情况可能有如下两种,如果对于根节点而言,选与不选的解是相同的,则说明这样肯定会是多解,另一种情况就是由于儿子节点的多解导致父亲节点的多解。所以我们可以用一个二维数组来标记某个节点由儿子节点更新到父亲节点的时候是不是有多解。对于选择父亲节点,那么可能导致的情况就是儿子节点不选的时候有多解,那么需要将这种多解的标记更新到父亲节点。对于不选择父亲节点,那么就有可能是儿子节点选与不选解都是相同的,或者儿子节点较大的那种选择有多解标记,此时我们标记父亲节点。具体代码如下:
/*
*author : csuchenan
*PROG : POJ3342
*Algorithm : TreeDP ,注意判重复的情况,
*这里如果某个点出现重复的情况那么就更新给父亲节点
*对于根节点只需要特判一下
*10792694 csuchenan 3342 Accepted 212K 0MS C++ 1955B 2012-09-11 11:12:53
*/
#include <cstdio>
#include <cstring>
#include <vector>
using std::vector ;
#define maxn 205
vector<int> G[maxn] ;
char name[205][105] ;
int dp[maxn][2] ;
bool special[maxn][2] ;
int n ;
int len ;
int insert(char * str){
strcpy(name[len] , str ) ;
len ++ ;
return len - 1 ;
}
int find(char *str){
int i(0) ;
while(i < len && strcmp(str , name[i]) != 0 )
i ++ ;
if(i == len )
return -1 ;
return i ;
}
void init(){
for(int i = 0 ; i <= n ; i ++){
G[i].clear() ;
}
memset(name , 0 , sizeof(name)) ;
memset(dp , 0 , sizeof(dp)) ;
memset(special , 0x1 , sizeof(special)) ;
len = 0 ;
}
inline int max(int x , int y){
return x > y ? x : y ;
}
void dfs(int v){
for(vector<int> :: size_type i = 0 ; i != G[v].size() ; i ++){
int u = G[v][i] ;
dfs(u ) ;
dp[v][0] += max(dp[u][1] , dp[u][0]) ;
dp[v][1] += dp[u][0] ;
if(dp[u][1] == dp[u][0]){
special[v][0] = 0 ;
}
else if(dp[u][0] > dp[u][1] && special[v][0]){
special[v][0] = special[u][0] ;
}
else if(dp[u][0]< dp[u][1] && special[v][0]){
special[v][0] = special[u][1] ;
}
if(special[v][1]){
special[v][1] = special[u][0] ;
}
}
dp[v][1] ++ ;
}
int main(){
char str[105] ;
//freopen("POJ3342.txt" , "r" , stdin) ;
while(scanf("%d" , &n) , n){
init() ;
scanf("%s" , str) ;
insert(str) ;
int p , q ;
for(int i = 1 ; i < n ; i ++){
scanf("%s" , str) ;
if( (p=find(str)) == -1 )
p = insert(str) ;
scanf("%s" , str) ;
if( (q=find(str)) == -1 )
q = insert(str) ;
//G[p].push_back(q) ;
G[q].push_back(p) ;
}
dfs(0) ;
int ans = max(dp[0][0] , dp[0][1]) ;
printf("%d " , ans ) ;
if(dp[0][0] == dp[0][1] )
puts("No") ;
else if( ((dp[0][0] > dp[0][1]) && !special[0][0]) ||
((dp[0][1] > dp[0][0]) && !special[0][1] ) )
puts("No") ;
else
puts("Yes") ;
}
return 0 ;
}