您的位置:首页 > 其它

HDOJ2412 Party at Hali-Bula (树形DP)

2012-07-20 17:04 141 查看
此题是经典树形DP题,没有上司的晚会。

公司所有人员之间的关系可以用一个树来表示,任何一个人(除了最大的boss外)都有且只有一个直接上司,现要开一个Party,邀请尽量多的人参加,要求任何人不得与直接上司同时参加。

抽象后的数学模型:在一棵树中,最多能选取多少结点,使得任何结点之间没有直接连边。

状态设计:d[i][0]表示在以i为根结点的子树中,在不选结点i的情况下最多能选取的结点数目,d[i][1]表示在以i为根结点的子树中,在选取结点i的情况下最多能选取的结点数目。

状态转移:d[i][0]=(max(d[j][0],d[j][1])),j为i的儿子结点,d[i][1]=∑(d[j][0]),j为i的儿子结点。

边界条件:当i没有儿子结点时,也即i为叶子结点,此时d[i][0]=0,d[i][1]=1。

需要注意的是判断最后的解是否唯一,此时可以用一个unique数组来同步记录,unique[i][0]记录以i为根结点且不选i时取最多的点是否唯一,unique[i][1]记录以i为根结点且选i时取最多结点是否唯一。在状态转移时同步更新unique数组。

View Code

#include <stdio.h>
#include <string.h>
#include <vector>
using namespace std;
#define MAX(a,b) ((a)>(b)?(a):(b))
#define N 200
#define LEN 101
char name
[LEN];
char s[LEN];
int n,top;
int p
,d
[2];
char unique
[2];
vector<int> son
;
int find()
{
for(int i=0;i<top;i++)    if(strcmp(name[i],s)==0)    return i;
strcpy(name[top++],s);
return top-1;
}
int dp(int i,int f)
{
int j,k,ans,cnt=son[i].size();
if(d[i][f]!=-1) return d[i][f];
if(f)
{
ans=1;
for(k=0;k<cnt;k++)
{
j=son[i][k];
ans+=dp(j,0),unique[i][f]&=unique[j][0];
}
}
else
{
ans=0;
for(k=0;k<cnt;k++)
{
j=son[i][k];
ans+=MAX(dp(j,0),dp(j,1));
if(dp(j,0)==dp(j,1))    unique[i][f]=false;
if(dp(j,0)>dp(j,1)) unique[i][f]&=unique[j][0];
else unique[i][f]&=unique[j][1];
}
}
return d[i][f]=ans;
}
void clear()
{
for(int i=0;i<n;i++)    son[i].clear();
}
int main()
{
int i,a,b;
bool flag;
while(scanf("%d",&n)&&n)
{
clear();
top=0;
scanf("%s",s);
p[find()]=-1;
for(i=1;i<n;i++)
{
scanf("%s",s);
a=find();
scanf("%s",s);
b=find();
p[a]=b;
son[b].push_back(a);
}
memset(d,-1,sizeof(d[0])*n);
memset(unique,1,sizeof(unique[0])*n);
a=dp(0,0);
b=dp(0,1);
if(a==b)    flag=false;
else if(a>b)    flag=unique[0][0];
else    flag=unique[0][1];
printf("%d %s\n",MAX(a,b),flag?"Yes":"No");
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: