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;
}
}
主要坑点
-
多组数据。感谢讨论区,让我成功避坑。
-
看讨论区很多大佬都打成了
YES
和NO
。这里注意是Yes
和No
。
完整代码
#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;
}
不要脸地求个赞
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现