近几天刚开始看树形DP,而这题算是一道经典题。
题目大意就不赘述,总而言之就是一棵树上选子节点就不能选父节点,然后要选尽量多的节点出来。
我们设dp[i][0]为以i为父节点时要加入这个节点,即选了这个boss,他的下属不能选,dp[i][1]为i为父节点时不能加入这个节点。
所以有dp[i][0]=dp[soni][1]求和 然后再加上它本身 即在数值上加1
dp[i][1]=max(dp[soni][1],dp[soni][0])求和 (soni为i的子节点)
然而此题还有一个问题就是此解是否唯一,我被这个问题卡了好久,想用一些复杂的方法去搞它 但后来参考了tec12的方法。
http://blog.csdn.net/tec12/archive/2010/08/10/5801741.aspx
首先对于每个点都有两个选择方法,若不加入这个点,那么必然加入子节点,而又若子节点加于不加时的值相等,那么当然重复了,对于最大的Boss,他不依赖任何节点,所以要特殊判断一下。
代码较长,是用链表实现的
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<map>
using namespace std;
const int N=210;
int dp[N][2];
int n;
struct node
{
int x;
node *next;
}tree[N];
node *newnode()
{
node *p=new node;
p->next=NULL;
return p;
}
void init()
{
int i;
for(i=1;i<=n;i++) tree[i].next=NULL;
memset(dp,0,sizeof(dp));
}
void insert(int a,int b)
{
node *p=&tree[a];
while(p->next) p=p->next;
node *q=newnode();
q->x=b;
p->next=q;
}
void dfs(int root)
{
int temp1=0,temp2=0;
node *p=tree[root].next;
int son;
while(p)
{
son=p->x;
dfs(son);
temp1+=dp[son][1];
temp2+=max(dp[son][0],dp[son][1]);
p=p->next;
}
dp[root][0]=temp1+1;
dp[root][1]=temp2;
}
bool check()
{
int i,son;
node *p;
for(i=1;i<=n;i++)
{
if(dp[i][1]>=dp[i][0])
{
p=tree[i].next;
while(p)
{
son=p->x;
if(dp[son][0]==dp[son][1]) return true;
p=p->next;
}
}
}
return false;
}
int main()
{
while(scanf("%d",&n)&&n)
{
string a,b;
int i,na,nb;
int t=1;
cin>>a;
init();
map <string,int> m;
m[a]=1;
for(i=1;i<=n-1;i++)
{
cin>>a>>b;
if(m.find(a)==m.end())
{
t++;
m[a]=t;
}
na=m[a];
if(m.find(b)==m.end())
{
t++;
m[b]=t;
}
nb=m[b];
insert(nb,na);
}
dfs(1);
int ans=0;
bool flag=false;
ans=max(dp[1][0],dp[1][1]);
flag=check();
if(dp[1][0]==dp[1][1]) flag=true;
printf("%d ",ans);
if(!flag) printf("Yes/n");
else printf("No/n");
}
return 0;
}