hdu 2412 Party at Hali-Bula (树形DP)

题意跟hdu1520一样,给定一棵树,要求选出若干个点,但如果选择了父节点跟儿子节点不可以同时选。。求可以选出的节点数的最大值,同时,判断该选法是否唯一;

分析:前半部分很容易实现,普通的树形dp,关键是如何判断是否唯一。

我们用flag[N][2]来记录每一个节点的情况

flag[i][j]为真,表示唯一

则可以这样判断

对于叶子结点, flag[k][0] = flag[k][1] = 1.
对于非叶子结点,
对于i的任一儿子j,若(dp[j][0] > dp[j][1] 且 flag[j][0] == 0) 或 (dp[j][0] < dp[j][1] 且 flag[j][1] == 0) 或 (dp[j][0] == dp[j][1]),则flag[i][0] = 0
对于i的任一儿子j有flag[j][0] = 0, 则flag[i][1] = 0
View Code
#include<iostream>
#include<algorithm>
#include<string.h>
#include<vector>
using namespace std;
const int N =210;
int n,num,dp[N][2];
vector<int> g[N];
bool flag[N][2];
typedef struct node
{
int cnt;
struct node *next[52];
}*tree,Trie;
tree root;
inline int GetNum(char *t){
tree p = root,newnode;
for(int i = 0;i < strlen(t); ++i){
int u = t[i] - 'a';
if(u<0) u=t[i]-'A'+26;
if(p->next[u]==NULL)
{
newnode=(tree)malloc(sizeof(Trie));
newnode->cnt=-1;
for(int j=0;j<52;j++)
newnode->next[j]=NULL;
p->next[u]=newnode;
p=newnode;
}
else
p = p->next[u];
}
if(p->cnt == -1) //该节点未出现过
p->cnt = num ++;
return p->cnt;
}
void init()
{
root=(tree)malloc(sizeof(Trie));
root->cnt=-1;
for(int j=0;j<52;j++)
root->next[j]=NULL;
num=1;
for(int i=0;i<=n;i++)
g[i].clear();
memset(dp,0,sizeof(dp));
memset(flag,true,sizeof(flag));
}
void dfs(int u)
{
int size=g[u].size();
for(int i=0;i<size;i++)
{
int v=g[u][i];
dfs(v);
dp[u][1]+=dp[v][0];
dp[u][0]+=max(dp[v][0],dp[v][1]);;
if(( dp[v][0]>dp[v][1] && !flag[v][0])|| (dp[v][0]<dp[v][1] && !flag[v][1]) || dp[v][0]==dp[v][1])
flag[u][0]=false;
if(!flag[v][0])
flag[u][1]=false;
}
dp[u][1]++;
}

int main()
{
char str[200],str1[200];
int a,b;
while(scanf("%d",&n)==1 && n)
{
init();
scanf("%s",str);
int s=GetNum(str);
for(int i=1;i<n;i++)
{
scanf("%s %s",str,str1);
a=GetNum(str);
b=GetNum(str1);
g[b].push_back(a);
}
dfs(s);
printf("%d ",max(dp[s][0],dp[s][1]));
if(dp[s][0]>dp[s][1] && flag[s][0])
puts("Yes");
else if(dp[s][1]>dp[s][0] && flag[s][1])
puts("Yes");
else puts("No");
}
return 0;
}
posted @ 2012-03-07 23:12  枕边梦  阅读(332)  评论(0编辑  收藏  举报