[CEOI2007] 树的匹配 Treasury 题解
前言
题目链接:洛谷。
题目简述
给一棵树,问你这棵树的最大匹配是多少,并且计算出有多少种最大匹配。
题目分析
先来考虑较简单的最大匹配数。对于某一个结点,它有以下三种状态:
- 不参与匹配;
- 和某一个儿子匹配;
- 和父亲匹配。
考虑使用树形 DP,我们发现,只需要知道一个孩子,和或不和自己匹配的最大匹配是多少,也即,在 DP 时,前两种状态在向上合并时是相同的——都不能和父亲构成一个新的匹配。那我们就可以记
以下考虑对于一个结点
对于
对于
对于方案数,我们再记
如果
如果和某一个孩子
注意,如果有多个
最后注意到题目最后一句话:
其中
的数据答案不超过 。
我们要使用高精度存
代码
略去了高精度 BigInteger
的实现。
#include <vector> #include <iostream> #include <cstdio> using namespace std; int n; vector<int> edge[1010]; BigInteger g[1010][2]; int f[1010][2]; void dfs(int now) { f[now][1] = 1, g[now][1] = 1; unsigned mx = 0, son = 0; for (unsigned i = 0; i < edge[now].size(); ++i) { int to = edge[now][i]; ++son, dfs(to); f[now][1] += f[to][0], g[now][1] *= g[to][0]; if (f[to][1] - f[to][0] > f[edge[now][mx]][1] - f[edge[now][mx]][0]) mx = i; } if (!son) return g[now][0] = 1, void(); f[now][0] = f[now][1] - 1 + f[edge[now][mx]][1] - f[edge[now][mx]][0]; static BigInteger suf[1010]; suf[edge[now].size()] = 1; for (unsigned i = edge[now].size() - 1; ~i; --i) suf[i] = suf[i + 1] * g[edge[now][i]][0]; BigInteger pre = 1; for (unsigned i = 0; i < edge[now].size(); ++i) { int to = edge[now][i]; if (f[to][1] - f[to][0] == f[edge[now][mx]][1] - f[edge[now][mx]][0]) g[now][0] += pre * suf[i + 1] * g[to][1]; pre *= g[edge[now][i]][0]; } if (f[edge[now][mx]][1] - f[edge[now][mx]][0] == 0) g[now][0] += g[now][1]; } signed main(){ scanf("%d", &n); for (int i = 1, u, v, k; i <= n; ++i) { scanf("%d%d", &u, &k); while (k--) scanf("%d", &v), edge[u].push_back(v); } dfs(1); printf("%d\n", f[1][0]); printf("%s", string(g[1][0]).c_str()); return 0; }
后记 & 反思
一道很水的题目,但是模拟赛时没写出来,寄。
本文作者:XuYueming,转载请注明原文链接:https://www.cnblogs.com/XuYueming/p/18295437。
若未作特殊说明,本作品采用 知识共享署名-非商业性使用 4.0 国际许可协议 进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现