Party at Hali-Bula UVA - 1220

树形DP基础 求最大独立集
题目描述:老板和员工不能同时选,问最大能选择多少人,并且种种方案是否唯一。
解题分析:定义两个数组 int dp[maxn][2];dp[u][1]表示以u为根节点的子树中选择u能得到的最大人数,dp[u][0]表示不选最大人数
int f[maxn][2];f[u][0]表示以u为根节点的子树,不选u的唯一性f[u][0]表示不选唯一,f[u][1]表示选唯一 .
则求解dp[u][1] = sum{dp[v][0} + 1。 v是U的子节点,只有全部的f[v][0] = 1,f[u][1] 才等于1,其他情况f[u][1] = 0; 求解dp[u][0] = sum(max(dp[v][0],dp[v][1])) , 当存在 dp[v][0] == dp[v][1]时,f[u][0] = 0; 当存在 dp[v][1] > dp[v][0]时,而f[v][1] = 0,此时也是f[u][0] = 0。
代码如下:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <map>
#include <vector>
#include <set>
using namespace std;

const int maxn = 200 + 10;
int n;
map<string,int > id;
set<string> getid;
int par[maxn];
vector <int> son[maxn];
int dp[maxn][2];//dp[u][1]表示以u为根节点的子树中选择u能得到的最大人数,dp[u][0]表示不选最大人数
int f[maxn][2];//f[u][0]表示以u为根节点的子树,不选u的唯一性f[u][0]表示不选唯一,f[u][1]表示选唯一

void solve1(int u)
{
    int sum = 0;
    bool is_uniq = true;
    for(int i = 0; i < son[u].size(); i++)
    {
        int v = son[u][i];
        sum += dp[v][0];
        if(f[v][0] != 1)
        {
            is_uniq = false;
        }
    }
    dp[u][1] = sum + 1;
    if(is_uniq) f[u][1] = 1;
    else f[u][1] = 0;
}

void solve0(int u)
{
    int sum = 0;
    bool is_uniq = true;
    for(int i = 0; i < son[u].size(); i++)
    {
        int v = son[u][i];
        if(dp[v][1] > dp[v][0])
        {
            sum += dp[v][1];
            if(f[v][1] != 1)
            {
                is_uniq = false;
            }
        }
        else if(dp[v][0] > dp[v][1])
        {
            sum += dp[v][0];
            if(f[v][0] != 1)
            {
                is_uniq = false;
            }
        }
        else
        {
            sum += dp[v][0];
            is_uniq = false;
        }
    }
    dp[u][0] = sum;
    if(is_uniq) f[u][0] = 1;
    else f[u][0] = 0;
}

void dfs(int u)
{
    if(son[u].size() == 0)
    {
        dp[u][1] = 1;
        f[u][1] = 1;
        dp[u][0] = 0;
        f[u][0] = 1;
    }
    else
    {
        for(int i = 0; i <son[u].size(); i++)
        {
            int v = son[u][i];
            dfs(v);
        }
        solve1(u);
        solve0(u);
    }
}

bool deal(int &ans)
{
    ans = 0;
    int is_uniq;
    for(int i = 0; i < n; i++)
    {
        for(int j = 0; j <= 1; j++)
        {
            if(dp[i][j] > ans)
            {
                ans = dp[i][j];
                is_uniq = f[i][j];
            }
            else if(dp[i][j] == ans)
            {
                is_uniq = 0;
            }
        }
    }
    if(is_uniq) return true;
    else return false;
}

void init()
{
    memset(dp,-1,sizeof(dp));
    memset(f,-1,sizeof(f));
    for(int i = 0; i < n; i++) son[i].clear();
    getid.clear();
    id.clear();
    string boss;
    cin >> boss;
    id[boss] = 0;
    string x,y;
    for(int i = 0; i < n-1 ; i++)
    {
        cin >> x >> y;
        if(!id.count(x))
        {
            getid.insert(x);
            int t = getid.size();
            id[x] = t;
        }
        if(!id.count(y))
        {
            getid.insert(y);
            int t = getid.size();
            id[y] = t;
        }
        par[id[x]] = id[y];
        son[id[y]].push_back(id[x]);
    }
}

int main()
{
    while(cin >> n && n)
    {
        init();
        dfs(0);
        int ans;
        if(deal(ans)) cout  << ans << " Yes" << endl;
        else cout << ans << " No" << endl;
    }
    return 0;
}
代码写的相当矬,但是足够清晰。


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值