POJ 3342 Party at Hali-Bula(树形DP)

题目链接

相比POJ 2342那题,增加了一问:最佳选择是否唯一的.

首先可根据雇员与老板的关系建立一颗树,老板做根节点,雇员是该根节点的儿子。



 如上面这棵简易的树,对于节点A有两种决策:  选与不选。  若选择A,则B 、C都不能选,问题转换为求所有以 “B、C的儿子为根节点的树” 子问题最优解之和。  若不选A, 则问题转换为求“以B、C为根节点"的子树的最优解之和。

写成状态方程就是:   d[ i ] = max { sigma ( d[ i 的儿子 ] )  ,   sigma ( d[ i 的孙子 ] )  + 1 }             d [ i ] 表示以 i 为根节点的树的最优解。

讲这个过程写成递归的函数就能得到答案。

类似的,可以递归地去判断最优解是否唯一,  在所有的做过的决策中,只要有一个  ”sigma ( d[ i 的儿子 ] )  == sigma ( d[ i 的孙子 ] )  + 1 “  答案就不是唯一的。

#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <algorithm>
#include <vector>
#include <map>
using namespace std;
const int MAXN=200+10;
vector<int>tree[MAXN];
map<string,int>mp;
int son[MAXN],gson[MAXN];
int num,N;

int Read_StoI()
{
    char tmp[105];
    scanf("%s",tmp);
    string s=tmp;
    if(mp.find(s)==mp.end()) mp[s]=++num;
    return mp[s];
}
void DFS(int x)
{
    son[x]=0,gson[x]=1;
    int i,m=tree[x].size();
    for(i=0;i<m;i++)
    {
        int p=tree[x][i];
        DFS(p);
        son[x] += max(son[p] , gson[p]);
        gson[x] += son[p];
    }
}
bool is_unique(int x)
{
    if(son[x] == gson[x]) return false;
    int i,m=tree[x].size();
    if(son[x] > gson[x])
    {
        for(i=0;i<m;i++)
        {
            if(!is_unique(tree[x][i])) return false;
        }
    }
    else
    {
        for(i=0;i<m;i++)
        {
            int Son=tree[x][i],j,SonNum=tree[Son].size();
            for(j=0;j<SonNum;j++)
            {
                if(!is_unique(tree[Son][j])) return false;
            }
        }
    }
    return true;
}
int main()
{
    while(scanf("%d",&N),N)
    {
        num=0;
        mp.clear();
        for(int i=0;i<=N;i++) tree[i].clear();
        Read_StoI();
        for(int i=1;i<N;i++)
        {
            int employee=Read_StoI(),boss=Read_StoI();
            tree[boss].push_back(employee);
        }
        DFS(1);
        int MaxNumOfGuest=max(son[1],gson[1]);
        printf("%d %s\n",MaxNumOfGuest,is_unique(1) ? "Yes" : "No" );
    }
    return 0;
}

当然,上面的代码可以改进,求最多人数和判断是否唯一可以结合在一起。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值