HDU 2412 Party at Hali-Bula (树形DP,map)

题意:n个人形成一个关系树,每个节点代表一个人,节点的父节点表示这个人的唯一上司,只有根没有上司。要求从这n个人中选择一部分,使得任意两个人之间没有直接的上下级关系,问最多可以选多少人?并且判断最优方案是否唯一,是则Yes,否则No。

题解:dp[i][0]表示不选择 i 时,以它为根的子树最多可选出的人数;dp[i][1]表示选择 i 时,以它为根的子树最多可选出的人数。sole[i][0]表示不选择 i 时,最优方案是否唯一;sole[i][1]表示选择 i 时,最优方案是否唯一。

PS:此ppt上有详细说明http://wenku.baidu.com/view/84164e1a227916888486d7d6.html?from=rec&pos=4&weight=1

#include<map>
#include<cstring>
#include<string>
#include<algorithm>
#include<iostream>
using namespace std;

map<string,int> name;
map<string,int>::iterator it;
int dp[500][2];
bool sole[500][2], visit[500];
struct Edge { int v, next; } edge[500];
int head[500], E, n;

void add_edge(int u, int v)
{
    edge[E].v = v;
    edge[E].next = head[u];
    head[u] = E++;
}

void DFS(int u, int father)
{
    if(visit[u]) return;
    if(head[u] == -1)
    {
        dp[u][0] = 0;
        dp[u][1] = 1;
        sole[u][0] = sole[u][1] = true;
        visit[u] = true;
        return;
    }
    visit[u] = true;
    dp[u][0] = 0; dp[u][1] = 1;
    sole[u][0] = sole[u][1] = true;
    for(int i = head[u]; i != -1; i = edge[i].next)
    {
        int v = edge[i].v;
        if(v == father) continue;
        if(!visit[v]) DFS(v, u);
        dp[u][0] += max(dp[v][0], dp[v][1]);
        dp[u][1] += dp[v][0];
        if(dp[v][0] > dp[v][1] && !sole[v][0]) sole[u][0] = false;
        if(dp[v][0] < dp[v][1] && !sole[v][1]) sole[u][0] = false;
        if(dp[v][0] == dp[v][1]) sole[u][0] = false;
        if(sole[v][0] == false) sole[u][1] = false;
    }
}

int main()
{
    string employee, boss;
    while(cin >> n)
    {
        if(n == 0) break;
        int i, c, u, v;
        c = E = 0;
        memset(head, -1, sizeof(head));
        memset(visit, 0, sizeof(visit));
        name.clear();
        cin >> boss;
        name.insert(pair<string, int>(boss, 0));
        for(i = 1; i < n; i++)
        {
            cin >> employee >> boss;
            it = name.find(employee);
            if(it ==  name.end())
            {
                name.insert(pair<string, int>(employee, ++c));
                u = c;
            }
            else u = it->second;

            it = name.find(boss);
            if(it ==  name.end())
            {
                name.insert(pair<string, int>(boss, ++c));
                v = c;
            }
            else v = it->second;

            add_edge(u, v);
            add_edge(v, u);
        }
        DFS(0, -1);
        if(dp[0][0] > dp[0][1])
            cout << dp[0][0] << (sole[0][0] ? " Yes" : " No") << endl;
        else if(dp[0][0] < dp[0][1])
            cout << dp[0][1] << (sole[0][1] ? " Yes" : " No") << endl;
        else
            cout << dp[0][0] << " No" << endl;
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值