题意:要举办一个舞会,雇员和它的直属上司不能同时参加。现在给出整个学校的关系图,要求出最多可以邀请多少人来参加聚会,并且判断方案是否唯一。
解题思路:典型的树形DP,用dp[f][0]和dp[f][1]分别表示是否邀请f。可以得到dp[f]的值和他的下属k存在的关系是:dp[f][0]+=Max(dp[k][0],dp[k][1]);dp[f][1]+=dp[k][0]。这里需要特别注意的是唯一标记flag的传递。flag为1表示不唯一,为0表示唯一。原则上,如果所取的值的flag为1,则标记当前值flag为1;如果所取值flag为0,则当前值的flag不变。需要特别注意的是:对于dp[f][0],需要判断dp[k][1]和dp[k][0]是否相等,如果相等,则标记dp[f][0]的flag为1。
#include<stdio.h>
#include<string.h>
#define N 205
char s[N][105];
struct node
{
int y;
int next;
}map[N];
struct point
{
int sum;
int flag;
}dp[N][2];
int head[N],mark[N];
int cnt,k;
int Max(int x,int y)
{
if(x>y) return x;
else return y;
}
int Find(char *s1)
{
for(int i=0;i<k;i++)
{
if(strcmp(s[i],s1)==0)
return i;
}
strcpy(s[k++],s1);
return k-1;
}
void AddEdge(int x,int y)
{
map[cnt].y=y;map[cnt].next=head[x];head[x]=cnt++;
return ;
}
void dfs(int f)
{
int u=head[f];
mark[f]=1;
dp[f][1].sum=1;
while(u!=-1)
{
int k=map[u].y;
if(!mark[k])
{
dfs(k);
dp[f][1].sum+=dp[k][0].sum;
if(dp[k][0].flag==1) dp[f][1].flag=1;
if(dp[k][1].sum>dp[k][0].sum)
{
dp[f][0].sum+=dp[k][1].sum;
if(dp[k][1].flag==1) dp[f][0].flag=1;
}
else if(dp[k][1].sum<dp[k][0].sum)
{
dp[f][0].sum+=dp[k][0].sum;
if(dp[k][0].flag==1) dp[f][0].flag=1;
}
else
{
dp[f][0].sum+=dp[k][1].sum;
dp[f][0].flag=1;
}
}
u=map[u].next;
}
return ;
}
int main()
{
int n;
while(scanf("%d",&n),n)
{
k=1;
char s1[N],s2[N];
scanf("%s",s[k++]);
memset(head,-1,sizeof(head));
cnt=0;
for(int i=1;i<n;i++)
{
scanf("%s%s",s1,s2);
int x,y;
x=Find(s1);
y=Find(s2);
AddEdge(y,x);
}
memset(dp,0,sizeof(dp));
memset(mark,0,sizeof(mark));
dfs(1);
int flag=0;
int ans;
if(dp[1][1].sum>dp[1][0].sum)
{
ans=dp[1][1].sum;
flag=dp[1][1].flag;
}
else if(dp[1][1].sum<dp[1][0].sum)
{
ans=dp[1][0].sum;
flag=dp[1][0].flag;
}
else
{
ans=dp[1][1].sum;
flag=1;
}
printf("%d ",ans);
if(!flag) printf("Yes\n");
else printf("No\n");
}
return 0;
}