【网络流二十四题 魔术球问题】【DAG 最小路径覆盖->最大流】【灵感】
来源:互联网 发布:融学软件下载 编辑:程序博客网 时间:2024/06/10 20:58
灵感
我们在解决网络流一类问题时
都要想限制条件和 S
T
是什么
问题模型: DAG 最小路径覆盖
转化模型 :最大流
由于是顺序放球,每根柱子上的球满足这样的特征,即下面的球编号小于上面球的编号。抽象成图论,把每个球看作一个顶点,就是编号较小的顶点向编号较大的顶点连接边,条件是两个球可以相邻,即编号之和为完全平方数。每根柱子看做一条路径,N
根柱子要覆盖掉所有点,一个解就是一个路径覆盖。
最小路径覆盖数随球的数量递增不递减,满足单调性,所以可以枚举答案(或二分答案),对于特定的答案求出最小路径覆盖数,一个可行解就是最小路径覆盖数等于 N
的答案,求出最大的可行解就是最优解。本问题更适合枚举答案而不是二分答案,因为如果顺序枚举答案,每次只需要在残量网络上增加新的节点和边,再增广一次即可。如果二分答案,就需要每次重新建图,大大增加了时间复杂度。
建图
枚举答案 A
,在图中建立节点 1 ... A
。如果对于 i < j
有 i + j
为一个完全平方数,连接一条有向边 (i, j)
。该图是有向无环图,求最小路径覆盖。如果刚好满足最小路径覆盖数等于 N
,那么 A
是一个可行解,在所有可行解中找到最大的 A
,即为最优解。
具体方法可以顺序枚举 A
的值,当最小路径覆盖数刚好大于 N
时终止,A - 1
就是最优解。
#include <bits/stdc++.h>using namespace std;const int N = 2e5 + 5, base = 1e5, inf = 0x7fffffff;struct Edge { int next, to, c; int mark, u;}e[N << 1];int n, s, t, lst = 0;bool check[N], used[3030][3030];int to[N], mark[N];int cnt = 1;int head[N], cur[N];void add(int u, int v) { e[++ cnt].to = v; e[cnt].c = 1; e[cnt].u = u; e[cnt].mark = 1; e[cnt].next = head[u]; head[u] = cnt; e[++ cnt].to = u; e[cnt].c = 0; e[cnt].u = v; e[cnt].mark = 0; e[cnt].next = head[v]; head[v] = cnt;}int dep[N];bool bfs(int x) { queue<int> q; memset(dep, 0, sizeof(dep)); dep[x] = 1; q.push(x); while(!q.empty()) { int u = q.front(); q.pop(); for (int i = head[u]; i; i = e[i].next) { int v = e[i].to; if (!dep[v] && e[i].c) { dep[v] = dep[u] + 1; q.push(v); } } } if (!dep[t]) return 0; return 1;}int dfs(int u, int flow) { if (u == t) return flow; for (int &i = cur[u]; i; i = e[i].next) { int v = e[i].to; if (dep[v] == dep[u] + 1 && e[i].c) { int nowflow = dfs(v, min(flow, e[i].c)); if (nowflow > 0) { e[i].c -= nowflow; e[i ^ 1].c += nowflow; return nowflow; } } } return 0;}int Dinic(int x) { int res = lst; while(bfs(s)) { for (int i = s; i <= x; i ++) cur[i] = head[i]; for (int i = base + 1; i <= base + x; i ++) cur[i] = head[i]; cur[t] = head[t]; while (int d = dfs(s, inf)) res += d; } lst = res; return x - res; // 总点数 = 最大匹配就是最小路径覆盖也就是柱子数 }int main() { memset(check, 0, sizeof(check)); memset(used, 0, sizeof(used)); memset(mark, 0, sizeof(mark)); scanf("%d", &n); s = 0, t = N - 1; for (int i = 1; i <= 60; i ++) check[i * i] = 1; int num = 0; while(1) { ++ num; add(s, num), add(num + base, t); for (int i = 1; i < num; i ++) if (check[i + num] == 1 && !used[i][num]) add(i, num + base), used[i][num] = 1; int ans = Dinic(num); if (ans > n) { printf("%d\n", num - 1); break; } } for (int i = 2; i <= cnt; i ++) if (e[i].mark == 1 && !e[i].c) to[e[i].u] = e[i].to - base, mark[e[i].to - base] = 1; for (int i = 1; i <= num - 1; i ++) { if (mark[i]) continue;; int k = i; while (k) { printf("%d ", k); k = to[k]; } printf("\n"); } return 0;}
阅读全文
0 0
- 【网络流二十四题 魔术球问题】【DAG 最小路径覆盖->最大流】【灵感】
- 【网络流二十四题 最小路径覆盖问题】【DAG 最小路径覆盖->最大流】
- [网络流24题] 04 魔术球问题 (有向无环图最小路径覆盖, 最大流)
- [网络流24题]魔术球问题(简化版) 最小路径覆盖+二分答案 + 很快的最大流
- 网络流二十四题之三 —— 最小路径覆盖问题(PATH)
- 线性规划与网络流24题の4 魔术球问题(最小路径覆盖)
- [网络流24题]魔术球问题 贪心||枚举答案+最小路径覆盖
- 网络流24题之四 魔术球问题 最小路径覆盖
- 【网络流24题】魔术球(最小路径覆盖+枚举)
- loj6003「网络流 24 题」魔术球(最小路径覆盖/打表贪心)
- [网络流24题] 03 最小路径覆盖问题(有向无环图最小路径覆盖,网络最大流)
- 网络流二十四题之四 —— 魔术球问题(BALL)
- loj6002网络流 24 题 最小路径覆盖 最大流
- [网络流24题][CODEVS1904]最小路径覆盖问题(最大流||匈牙利算法)
- 【网络流二十四题 方格取数问题】【二分图点权最大独立集->最小割】
- 【网络流二十四题 骑士共存问题】【二分图点权最大独立集->最小割】
- 网络流24题3最小路径覆盖问题(洛谷 P2764 最小路径覆盖问题)
- 最小路径覆盖问题 (网络流解法)
- Mybatis分页处理
- 深入浅出: Java回调机制(异步)
- SYSU Matrix上的选做题——多柱汉诺塔
- poj 3190
- 自定义Dialog从底部滑入,滑出。
- 【网络流二十四题 魔术球问题】【DAG 最小路径覆盖->最大流】【灵感】
- python爬虫学习 之 定向爬取 淘宝商品价格
- 单例模式(Singleton模式)
- 蓝桥杯 基础练习 数列排序
- 英伟达的 VR 探索之路:图像渲染
- python 如何引用modules
- [以太坊源代码分析]III. 挖矿和共识算法的奥秘
- cocos 线程相关
- android studio 链接不上手机