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;
}
代码写的相当矬,但是足够清晰。


全部评论

相关推荐

浪子陪都:简历最优秀的地方放到了后面,国奖,校级奖学金这些是最亮眼的。说明你跟同级别的学生不一样。 建议台灯这个,PCB布局布线这个词汇不专业,业内是PCB Layout,第二,单片机的板子一般不用考虑SI,PI 都是低速信号,只要遵循3W原则就好了。 单片机的项目太low了,技能这块,你要看一下BOSS直聘的招聘要求,按照别人的要求写,一些关键词可以增加你简历被检索到的概率。 主修课程不用写,这个没有人去关注的。
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客企业服务