P2765 魔术球问题(最小路径点覆盖)
这个题目很不同,它给出的是柱子的数量,要反推球的数量。
可以这样认为,给出边数,求上面的点数。
- 每次只能在某根柱子的最上面放球 -> 点的连接方式是一串串的,易发现图是个 DAG;
然后好像没什么可推的性质了。
题目没给出点数,那肯定要去不断试不同的点数 n ,每次进行判定是否符合条件,这是很朴素的想法。
可以对当前 n 讨论,
因为图建模要保证任意两点编号和为完全平方数,考虑
发现图建出来,存在很多条子路径上任意两点都满足题目性质,而要用柱子串住这些点,
不就是 最小路径点覆盖 问题吗?
现在推判定条件,求最多能有多少个点能被 m 条路径覆盖,
- 当 res < m,显然不够,还要加点;
- 当 res = m,可能还有更大的答案,继续加点;
- 当 res = m + 1,这样考虑,这个条件等价于多出刚好一个点,需要刚好多加一条边覆盖,而这个状态上再去掉这个点,就一定是 m 条边能覆盖的最大点数,否则矛盾;
所以当判定符合条件后,n-1 便是答案,注意:因为改变了点,所以之后要再跑一边增广。
然鹅,这样做会 T,
显然
所以不需要每次推倒重来,
同样的,因为图是连续的,所以很多答案是之前跑增广就得到的匹配答案,对当前,如果已经匹配有点了,直接更新即可。
#include <bits/stdc++.h> #define re register int using namespace std; const int N = 2e3; struct edge { int to, next; }e[N * N]; int top, h[N]; int match[N], rev_m[N], res; int m, n; bool vis[N], used[N]; map<int, bool> f; inline void add(int x, int y) { e[++ top] = (edge){y, h[x]}; h[x] = top; } bool dfs(int u) { for (re i = h[u]; i; i = e[i].next) { int v = e[i].to; if (vis[v] || v > n) continue; vis[v] = true; if (!match[v] || dfs(match[v])) { match[v] = u; rev_m[u] = v; return true; } } return false; } inline int work() { res = 0; for (re i = 1; i <= n; i ++) { memset(vis, false, sizeof(vis)); res += (rev_m[i] || dfs(i)); // 优化 2 } return n - res; } inline void pass(int u) { cout << u << ' '; used[u] = true; if (!rev_m[u] || used[rev_m[u]]) return; pass(rev_m[u]); } inline void print() { for (re i = 1; i <= n; i ++) if (!used[i]) { pass(i); cout << '\n'; } } int main() { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); cin >> m; for (re i = 1; i <= N; i ++) f[i * i] = true; while (++ n) { for (re i = 1; i < n; i ++) if (f[i + n]) add(i, n); // 优化 1 if (work() == m + 1) { n --; cout << n << '\n'; break; } } work(); print(); return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!