UVA1220 Hali-Bula的晚会 Party at Hali-Bula

题目大意

给定一棵树,请选取最多的结点,使任意两个结点之间的高度差不为 $1$。请求出最多的节点数以及选取结点方案是否唯一。

(即增加了唯一性判断的最大独立集问题)

思路分析

树形dp简单板子题。

对于每一个结点 $u$,都有选择或不选择 $2$ 种情况。我们设

  • $dp[u][0]$ 表示不选择结点 $u$ 时,在以 $u$ 为根的子树中选择的最大人数。

  • $dp[u][1]$ 表示选择结点 $u$ 时,在以 $u$ 为根的子树中选择的最大人数。

  • $unq[u][0]$ 表示不选择结点 $u$ 时,以结点 $u$ 为根子树方案的唯一性。$0$ 表示唯一,$1$ 表示不唯一。

  • $unq[u][1]$ 表示选择结点 $u$ 时,以结点 $u$ 为根子树方案的唯一性。$0$ 表示唯一,$1$ 表示不唯一。

经过分析,得到状态转移方程如下:

  • 若不选择当前结点 $u$,则它的所有子节点 $v$ 都可选可不选,取最大值即可。如果 $dp[v][0]=dp[v][1]$,说明 $unq[u][0]$ 不唯一,否则唯一。

    $$dp[u][0] = dp[u][0] +\max(dp[v][0],dp[v][1])$$

  • 若选择当前结点 $u$,则所有子节点 $v$ 均不可选。若 $unq[v][0]$ 方案不唯一,$unq[u][1]$ 也不唯一,否则唯一。

    $$dp[u][1]=dp[u][1]+dp[v][0]$$


状态转移方程已经推出,只需要进行一次深搜即可。这里采用邻接表 vector<vector<int>> 存储树,便于进行搜索。

搜索部分代码:

void dfs(int node) {
    dp[node][0] = 0;
    dp[node][1] = 1;
    for (int i = 0; i < tree[node].size(); i++) {
        int to = tree[node][i];
        dfs(to);
        if (dp[to][0] > dp[to][1]) {
            dp[node][0] += dp[to][0];
            if (unq[to][0] == 0) unq[node][0] = 0;
        } else if (dp[to][0] < dp[to][1]) {
            dp[node][0] += dp[to][1];
            if (unq[to][1] == 0) unq[node][0] = 0;
        } else if (dp[to][0] == dp[to][1]) {
            dp[node][0] += dp[to][0];
            unq[node][0] = 0;
        }
        dp[node][1] += dp[to][0];
        if (unq[to][0] == 0) unq[node][1] = 0;
    }
}

主要坑点

  • 多组数据。感谢讨论区,让我成功避坑。

  • 看讨论区很多大佬都打成了 YESNO。这里注意是 YesNo

完整代码

#include <bits/stdc++.h>

using namespace std;

const int maxn = (1 << 22) + 1;

int n, k;
int dp[maxn][2];
int unq[maxn][2];

string root, fat, son;
vector<vector<int>> tree (maxn);
map<string, int> table;

void init() {
    k = 1;
    memset(dp, 0, sizeof(dp));
    memset(unq, 1, sizeof(unq));
    table.clear();
    for (int i = 0; i <= n; i++) {
        tree[i].clear();
    }
}

void dfs(int node) {
    dp[node][0] = 0;
    dp[node][1] = 1;
    for (int i = 0; i < tree[node].size(); i++) {
        int to = tree[node][i];
        dfs(to);
        if (dp[to][0] > dp[to][1]) {
            dp[node][0] += dp[to][0];
            if (unq[to][0] == 0) unq[node][0] = 0;
        } else if (dp[to][0] < dp[to][1]) {
            dp[node][0] += dp[to][1];
            if (unq[to][1] == 0) unq[node][0] = 0;
        } else if (dp[to][0] == dp[to][1]) {
            dp[node][0] += dp[to][0];
            unq[node][0] = 0;
        }
        dp[node][1] += dp[to][0];
        if (unq[to][0] == 0) unq[node][1] = 0;
    }
}

int main() {
    while (cin >> n && n) {
        init();
        cin >> root;
        table[root] = k++;
        tree[0].push_back(table[root]);
        for (int i = 1; i < n; i++) {
            cin >> son >> fat;
            if (table.count(son) == 0) table[son] = k++;
            if (table.count(fat) == 0) table[fat] = k++;
            tree[table[fat]].push_back(table[son]);
        }
        dfs(0);
        cout << dp[0][0] << " " << (unq[0][0] ? "Yes" : "No") << endl;
    }
    return 0;
}

不要脸地求个赞

posted @   TernaKagiri  阅读(3)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示