[swustoj1739] 魔术球问题 (最大流,最小路径覆盖)

题目链接:https://www.oj.swust.edu.cn/problem/show/1739

从1开始枚举球的个数,每次从残余网络更新总流量,最小路径覆盖刚好大于n时ret-1便是最多球。

之后根据容量为0的边找回匹配边即可。

用x << 1和x << 1 | 1拆点 比较方便。

  1 #include <bits/stdc++.h>
  2 using namespace std;
  3
  4 typedef struct Edge {
  5     int u, v, w, next;
  6 }Edge;
  7
  8 const int inf = 0x7f7f7f7f;
  9 const int maxn = 100200;
 10
 11 int cnt, dhead[maxn];
 12 int cur[maxn], dd[maxn];
 13 Edge dedge[maxn<<1];
 14 // bool vis[maxn]; // 记录经过的点
 15 int S, T, N;
 16
 17 void init() {
 18     memset(dhead, -1, sizeof(dhead));
 19     for(int i = 0; i < maxn; i++) dedge[i].next = -1;
 20     S = 0; cnt = 0;
 21 }
 22
 23 void adde(int u, int v, int w, int c1=0) {
 24     dedge[cnt].u = u; dedge[cnt].v = v; dedge[cnt].w = w;
 25     dedge[cnt].next = dhead[u]; dhead[u] = cnt++;
 26     dedge[cnt].u = v; dedge[cnt].v = u; dedge[cnt].w = c1;
 27     dedge[cnt].next = dhead[v]; dhead[v] = cnt++;
 28 }
 29
 30 bool bfs(int s, int t, int n) {
 31     // memset(vis, 0, sizeof(vis));
 32     queue<int> q;
 33     for(int i = 0; i < n; i++) dd[i] = inf;
 34     dd[s] = 0;
 35     q.push(s);
 36     while(!q.empty()) {
 37         int u = q.front(); q.pop();
 38         for(int i = dhead[u]; ~i; i = dedge[i].next) {
 39             if(dd[dedge[i].v] > dd[u] + 1 && dedge[i].w > 0) {
 40                 dd[dedge[i].v] = dd[u] + 1;
 41                 // vis[dedge[i].v] = 1;
 42                 if(dedge[i].v == t) return 1;
 43                 q.push(dedge[i].v);
 44             }
 45         }
 46     }
 47     return 0;
 48 }
 49
 50 int dinic(int s, int t, int n) {
 51     int st[maxn], top;
 52     int u;
 53     int flow = 0;
 54     while(bfs(s, t, n)) {
 55         for(int i = 0; i < n; i++) cur[i] = dhead[i];
 56         u = s; top = 0;
 57         while(cur[s] != -1) {
 58             if(u == t) {
 59                 int tp = inf;
 60                 for(int i = top - 1; i >= 0; i--) {
 61                     tp = min(tp, dedge[st[i]].w);
 62                 }
 63                 flow += tp;
 64                 for(int i = top - 1; i >= 0; i--) {
 65                     dedge[st[i]].w -= tp;
 66                     dedge[st[i] ^ 1].w += tp;
 67                     if(dedge[st[i]].w == 0) top = i;
 68                 }
 69                 u = dedge[st[top]].u;
 70             }
 71             else if(cur[u] != -1 && dedge[cur[u]].w > 0 && dd[u] + 1 == dd[dedge[cur[u]].v]) {
 72                 st[top++] = cur[u];
 73                 u = dedge[cur[u]].v;
 74             }
 75             else {
 76                 while(u != s && cur[u] == -1) {
 77                     u = dedge[st[--top]].u;
 78                 }
 79                 cur[u] = dedge[cur[u]].next;
 80             }
 81         }
 82     }
 83     return flow;
 84 }
 85
 86 int k, n;
 87 int path[maxn];
 88 bool vis[maxn];
 89
 90 bool ok(int x) {
 91     int y = (int)sqrt(x);
 92     return x == y * y;
 93 }
 94
 95 int main() {
 96     // freopen("in", "r", stdin);
 97     while(~scanf("%d", &n)) {
 98         init();
 99         S = 0, T = 10001, N = T + 1;
100         int ret = 0;
101         int flow = 0;
102         while(1) {
103             ret++;
104             for(int i = 1; i < ret; i++) {
105                 if(ok(i+ret)) adde(i<<1, (ret<<1)|1, 1);
106             }
107             adde(S, ret<<1, 1);
108             adde((ret<<1)|1, T, 1);
109             flow += dinic(S, T, N);
110             if(ret - flow > n) break;
111         }
112         memset(vis, 0, sizeof(vis));
113         memset(path, -1, sizeof(path));
114         printf("%d\n", ret-1);
115         int q = 0;
116         for(int i = 1; i < ret; i++) {
117             for(int j = dhead[i<<1]; ~j; j=dedge[j].next) {
118                 if(!dedge[j].w) {
119                     path[i] = dedge[j].v >> 1;
120                     break;
121                 }
122             }
123         }
124         for(int i = 1; i < ret; i++) {
125             if(!vis[i]) {
126                 vis[i] = 1;
127                 printf("%d", i);
128                 int j = path[i];
129                 while(j != 0 && j != T) {
130                     printf(" %d", j);
131                     vis[j] = 1;
132                     j = path[j];
133                 }
134                 printf("\n");
135             }
136         }
137     }
138     return 0;
139 }
时间: 2025-01-31 06:55:11

[swustoj1739] 魔术球问题 (最大流,最小路径覆盖)的相关文章

POWOJ 1739: 魔术球问题 DAG最小路径覆盖转最大流

1739: 魔术球问题 题意: 假设有n根柱子,现要按下述规则在这n根柱子中依次放入编号为1,2,3,...的球. (1)每次只能在某根柱子的最上面放球. (2)在同一根柱子中,任何2个相邻球的编号之和为完全平方数. 试设计一个算法,计算出在n根柱子上最多能放多少个球.对于给定的n,计算在n根柱子上最多能放多少个球. tags: 对大佬来说应该是很素的一道题,但某还是花了好多时间才做出来.. 一开始连建图都有点懵,然后最小路径还是新概念,最大匹配也不太懂,最大流倒是会一点. 然后要打印答案,也不

cogs_396_魔术球问题_(最小路径覆盖+二分图匹配,网络流24题#4)

描述 http://cojs.tk/cogs/problem/problem.php?pid=396 连续从1开始编号的球,按照顺寻一个个放在n个柱子上,\(i\)放在\(j\)上面的必要条件是\(i+j\)是一个完全平方数.问做多能放到几号球. 分析 cogs是简化版,我在网上找了个完整版的测试数据,要求输出方案... 求最大放几号球不方便,我们考虑枚举最大的球号,计算最少需要多少柱子. 我们对于满足\(j<i\)且\(i+j\)是一个完全平方数的\(i,j\),从\(j\)向\(i\)连一条

LiberOJ 6003. 「网络流 24 题」魔术球 贪心或者最小路径覆盖

6003. 「网络流 24 题」魔术球 内存限制:256 MiB时间限制:1000 ms标准输入输出 题目类型:传统评测方式:Special Judge 上传者: 匿名 提交提交记录统计讨论测试数据 题目描述 假设有 n nn 根柱子,现要按下述规则在这 n nn 根柱子中依次放入编号为 1,2,3,4,? 1, 2, 3, 4, \cdots1,2,3,4,? 的球. 每次只能在某根柱子的最上面放球. 在同一根柱子中,任何 2 22 个相邻球的编号之和为完全平方数. 试设计一个算法,计算出在 

[loj #6003]「网络流 24 题」魔术球 二分图最小路径覆盖,网络流

#6003. 「网络流 24 题」魔术球 内存限制:256 MiB时间限制:1000 ms标准输入输出 题目类型:传统评测方式:Special Judge 上传者: 匿名 提交提交记录统计讨论测试数据 题目描述 假设有 n nn 根柱子,现要按下述规则在这 n nn 根柱子中依次放入编号为 1,2,3,4,? 1, 2, 3, 4, \cdots1,2,3,4,? 的球. 每次只能在某根柱子的最上面放球. 在同一根柱子中,任何 2 22 个相邻球的编号之和为完全平方数. 试设计一个算法,计算出在

【最小路径覆盖】【二分图】【最大流】【Dinic】bzoj2150 部落战争

裸的最小路径覆盖. 把每个点拆点,变成二分图. 对于可以连边的点对(i,j):i->j'(1); 对于任意一点i,若i点为'.':S->i(1),i'->T(1); 答案为所有'.'的数量-最大流(最大匹配数). 引用证明: 路径覆盖中的每条简单路径除了最后一个顶点之外都有唯一的后继和它对应:因此匹配边数就是非路径结尾的结点数:因此,匹配边数达到最大时,非路径结尾的结点数大道最大,故路径结尾的节点数目最少. #include<cstdio> #include<cstri

【网络流24题 #03】最小路径覆盖问题

题目链接:最小路径覆盖问题 哇 卡在输出也是醉了 重要结论:最小路径覆盖数 = 结点数(拆成边之前) -  最大流 本题也是点拆边 与[网络流24题 #04]魔术球问题 有异曲同工之妙 void output(int x){ if(x >= S) return ; printf("%d ", x >> 1); for(int i = head[x]; i != -1; i = edge[i].next) if(!edge[i].w && edge[i]

COGS728. [网络流24题] 最小路径覆盖问题

算法实现题8-3 最小路径覆盖问题(习题8-13) ´问题描述: 给定有向图G=(V,E).设P是G的一个简单路(顶点不相交)的集合.如果V中每个顶点恰好在P的一条路上,则称P是G的一个路径覆盖.P中路径可以从V的任何一个顶点开始,长度也是任意的,特别地,可以为0.G的最小路径覆盖是G的所含路径条数最少的路径覆盖.设计一个有效算法求一个有向无环图G的最小路径覆盖. 提示: 设V={1,2,...  ,n},构造网络G1=(V1,E1)如下: 每条边的容量均为1.求网络G1的(x0,y0)最大流.

Codeforces 618D Hamiltonian Spanning Tree(树的最小路径覆盖)

题意:给出一张完全图,所有的边的边权都是 y,现在给出图的一个生成树,将生成树上的边的边权改为 x,求一条距离最短的哈密顿路径. 先考虑x>=y的情况,那么应该尽量不走生成树上的边,如果生成树上有一个点的度数是n-1,那么必然需要走一条生成树上的边,此时答案为x+y*(n-2). 否则可以不走生成树上的边,则答案为y*(n-1). 再考虑x<y的情况,那么应该尽量走生成树上的边,由于树上没有环,于是我们每一次需要走树的一条路,然后需要从非生成树上的边跳到树的另一个点上去, 显然跳的越少越好,于

[网络流专练3][最小路径覆盖问题]

题目描述 «问题描述: 给定有向图G=(V,E).设P 是G 的一个简单路(顶点不相交)的集合.如果V 中每个顶点恰好在P 的一条路上,则称P是G 的一个路径覆盖.P 中路径可以从V 的任何一个顶点开始,长度也是任意的,特别地,可以为0.G 的最小路径覆盖是G 的所含路径条数最少的路径覆盖.设计一个有效算法求一个有向无环图G 的最小路径覆盖.提示:设V={1,2,.... ,n},构造网络G1=(V1,E1)如下: 每条边的容量均为1.求网络G1的( 0 x , 0 y )最大流. «编程任务: