【树形dp】hdu 2412 Party at Hali-Bula

分析明天在写,先睡觉!

【key】
建树vector<int>child[N] (类似于邻接矩阵存储图)
上下级关系决定有向图
字典树用map容器作映射解决


动态规划递推关系:
dp[u][1]+=dp[child[u][i]][0];
dp[u][0]+=max(dp[child[u][i]][1],dp[child[u][i]][0]);


唯一性判定有点难!
也用二维数组递推关系解决:


1.不取当前节点的唯一性取决于你要选取那个子节点的唯一性以及是否选取他,根本上取决于动态数组dp的表达式关系;
if(dp[child[u][i]][1]==dp[child[u][i]][0]) f[u][0]=0;
else if(dp[child[u][i]][0]>dp[child[u][i]][1]&&f[child[u][i]][0]==0) f[u][0]=0;
else if(dp[child[u][i]][0]<dp[child[u][i]][1]&&f[child[u][i]][1]==0) f[u][0]=0;


2.取当前节点u的唯一性取决于是否存在子节点不唯一,有一个子节点不唯一,该节点取1的状态就为0(0表示不唯一,1唯一)
if(f[child[u][i]][0]==0) f[u][1]=0;


#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <climits>
#include <map>
#include <vector>
#include <list>
#include <stack>
#include <queue>
#define eps 1e-9
#define pi acos(-1)
#define clr(k,v) memset(k,v,sizeof(k));
using namespace std;
typedef long long ll;
const int maxn=410;
const int mod=1000000009;
const int SZ = 1<<20;/*
struct fastio{
char inbuf[SZ];char outbuf[SZ];fastio(){//¸ßËÙ»º´æ
    setvbuf(stdin,inbuf,_IOFBF,SZ);
    setvbuf(stdout,outbuf,_IOFBF,SZ);
}}io;*/
vector<int>child[maxn];
map<string,int>mp;//做一个string->int的映射,方便建立child[]
int dp[maxn][2];//dp[i][0]不包含编号为i的子树最大集合,dp[i][1]包含i的子树最大集合
bool f[maxn][2];//唯一性判断,也具有树节点关联性,f[i][]==1子树唯一,0有多条
void dfs(int u){
  int size=child[u].size();
  if(size==0){
    dp[u][0]=0;
    dp[u][1]=1;
    return;//递归基
  }
  for(int i=0;i<size;++i){
    dfs(child[u][i]);//遍历完第i个节点后才能处理该节点的dp值
    dp[u][1]+=dp[child[u][i]][0];
    dp[u][0]+=max(dp[child[u][i]][1],dp[child[u][i]][0]);
    if(dp[child[u][i]][1]==dp[child[u][i]][0]) f[u][0]=0;
    else if(dp[child[u][i]][0]>dp[child[u][i]][1]&&f[child[u][i]][0]==0) f[u][0]=0;
    else if(dp[child[u][i]][0]<dp[child[u][i]][1]&&f[child[u][i]][1]==0) f[u][0]=0;
    if(f[child[u][i]][0]==0) f[u][1]=0;
  }
  dp[u][1]++;//可以提前初始化,也可放在这里
}
int main()
{
  // freopen("input.txt","r",stdin);
   int n;
   while(cin>>n&&n){
     clr(dp,0);
     clr(f,1);//初始化都唯一
     int top=1;
     string str1,str2;
     cin>>str1;
     mp[str1]=top++;
     for(int i=1;i<n;i++){
        cin>>str1>>str2;
        if(!mp[str1]) mp[str1]=top++;
        if(!mp[str2]) mp[str2]=top++;//做一个mp表格
        child[mp[str2]].push_back(mp[str1]);
     }
     dfs(1);
     for(int i=1;i<=n;i++) child[i].clear();
     mp.clear();
     bool ok=true;
     if(dp[1][1]>dp[1][0]) ok=f[1][1];
     else if(dp[1][1]<dp[1][0]) ok=f[1][0];
     else ok=false;
     printf("%d ",max(dp[1][0],dp[1][1]));//dp[i][0]不包含编号为i的子树最大集合,dp[i][1]包含i的子树最大集合
     puts(ok?"Yes":"No");
   }
   return 0;
}





  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值