poj 3342 Party at Hali-Bula

本文介绍了一种使用树形动态规划解决聚会参与人数优化问题的方法,通过递归遍历树状结构并进行状态转移,计算不同情况下聚会的最大参与人数。

简单的树形dp, 先建好图, 然后在dfs的过程中进行dp      dp[i][j]   标记j表示人的序号   i有2种状态 1, 0,分别表示此人是否参加聚会。 

具体的dp过程   当i为1是, 他的孩子状态必须全部为0, 如果为1是则无硬性要求,只要求人最多。  这题唯一麻烦的便是唯一性的判断,要是如果j取其孩子时,如果孩子不唯一,则j肯定不唯一,这是必然的道理。  具体的判断过程

        if(!uni[0][y])    //1的时候只需要看其子节点
            uni[1][x] = false;
        if(dp[0][y] == dp[1][y])    //0的时候还需要看那种孩子最大,且是否相等。
        {
          dp[0][x] += dp[0][y];
          uni[0][x] = false;
        }
        else if(dp[0][y] > dp[1][y])
        {
            if(!uni[0][y])
               uni[0][x] = false;
               dp[0][x] += dp[0][y];
        }
        else {
            if(!uni[1][y])
                uni[0][x] = false;
            dp[0][x] += dp[1][y];
        }
具体代码

#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<map>
using namespace std;
const int Maxn = 210;

int MAX(int x,int y) {
    return x>y?x:y;
}

vector<int> g[Maxn];
char str[110];
int n, di, dp[2][Maxn];
bool uni[2][Maxn];

void dfs(int x) {
    int y;
    for(int k = 0; k < g[x].size(); ++k)
    {
        y = g[x][k];
        dfs(y);
    }
    dp[1][x] = 1, dp[0][x] = 0;
    for(int k = 0; k < g[x].size(); ++k)
    {
        y = g[x][k];
        dp[1][x] += dp[0][y];
        if(!uni[0][y])
            uni[1][x] = false;
        if(dp[0][y] == dp[1][y])
        {
          dp[0][x] += dp[0][y];
          uni[0][x] = false;
        }
        else if(dp[0][y] > dp[1][y])
        {
            if(!uni[0][y])
               uni[0][x] = false;
               dp[0][x] += dp[0][y];
        }
        else {
            if(!uni[1][y])
                uni[0][x] = false;
            dp[0][x] += dp[1][y];

        }
    }
 }

int main(void)
{
    while(scanf("%d",&n), n) {
    map<string,int> man;
    for(int i = 1; i <= n; ++i)
        g[i].clear();
    scanf("%s",str);
    di = 0;
    if(man.find(str) == man.end())
        man[str] = ++di;
    int now, next;
    for(int i = 2; i <= n; ++i) {
        scanf("%s", str);
    if(man.find(str) == man.end())
        man[str] = ++di;
     now = man[str];
        scanf("%s", str);
     if(man.find(str) == man.end())
        man[str] = ++di;
      next = man[str];
      g[next].push_back(now);
    }
    memset(uni, true, sizeof(uni));
    memset(dp, 0, sizeof(dp));
    dfs(1);
    bool flag = false;
    if(dp[1][1] == dp[0][1])
        flag = true;
    else if(dp[1][1] > dp[0][1])
    {
        if(!uni[1][1])
            flag = true;
    }
    else
    {
        if(!uni[0][1])
            flag = true;
    }
    cout<<MAX(dp[1][1], dp[0][1]);
    if(flag)
      cout<<" No"<<endl;
    else
        cout<<" Yes"<<endl;
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值