P2765 魔术球问题(网络流24题)

Posted Fitz

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P2765 魔术球问题(网络流24题)相关的知识,希望对你有一定的参考价值。

题目描述

?问题描述:

假设有n根柱子,现要按下述规则在这n根柱子中依次放入编号为1,2,3,...的球。

(1)每次只能在某根柱子的最上面放球。

(2)在同一根柱子中,任何2个相邻球的编号之和为完全平方数。

试设计一个算法,计算出在n根柱子上最多能放多少个球。例如,在4 根柱子上最多可放11 个球。

?编程任务:

对于给定的n,计算在n根柱子上最多能放多少个球。

输入输出格式

输入格式:

 

第1 行有1个正整数n,表示柱子数。

 

输出格式:

 

程序运行结束时,将n 根柱子上最多能放的球数以及相应的放置方案输出。文件的第一行是球数。接下来的n行,每行是一根柱子上的球的编号。

 

输入输出样例

输入样例#1: 复制
4
输出样例#1: 复制
11
1 8
2 7 9
3 6 10
4 5 11


这题其实和上一题差不多,不过这个是反正过来的。
这题需要转化一下
求对于给定的n,计算在n根柱子上最多能放多少个球。
一开始无从下手,但是它给了一个条件
在同一根柱子中,任何2个相邻球的编号之和为完全平方数。
将他转化为二分图,
求最大匹配数,
点数=两点最大匹配数+最小路径覆盖数,
它给的n就是最小路径覆盖数,网络流跑最大匹配数
然后点数就出来了
这里采取的是枚举的方法
求点数,

然后就是上代码
  1 #include <cstdio>
  2 #include <algorithm>
  3 #include <vector>
  4 #include <queue>
  5 #include <cstring>
  6 #include <string>
  7 #include <cmath>
  8 #include <map>
  9 using namespace std;
 10 const int maxn = 2e5 + 10;
 11 const int INF = 1e9 + 7;
 12 typedef long long LL;
 13 int st = 0, ed = 4000;
 14 struct node {
 15     int from, to, cap, flow;
 16 };
 17 struct Dinic {
 18     int n, m, s, t;
 19     vector<node>nodes;
 20     vector<int>g[maxn];
 21     int vis[maxn], d[maxn], cur[maxn];
 22     void clearall(int n) {
 23         for (int i = 0 ; i < n ; i++) g[i].clear();
 24         nodes.clear();
 25     }
 26     void clearflow() {
 27         int len = nodes.size();
 28         for (int i = 0 ; i < len ; i++) nodes[i].flow = 0;
 29     }
 30     void add(int from, int to, int cap) {
 31         nodes.push_back((node) {
 32             from, to, cap, 0
 33         });
 34         nodes.push_back((node) {
 35             to, from, 0, 0
 36         });
 37         m = nodes.size();
 38         g[from].push_back(m - 2);
 39         g[to].push_back(m - 1);
 40     }
 41     bool bfs() {
 42         memset(vis, 0, sizeof(vis));
 43         queue<int>q;
 44         q.push(s) ;
 45         d[s] = 0;
 46         vis[s] = 1;
 47         while(!q.empty()) {
 48             int x = q.front();
 49             q.pop();
 50             int len = g[x].size();
 51             for (int i = 0 ; i < len ; i++) {
 52                 node & e = nodes[g[x][i]];
 53                 if (!vis[e.to] && e.cap > e.flow ) {
 54                     vis[e.to] = 1;
 55                     d[e.to] = d[x] + 1;
 56                     q.push(e.to);
 57                 }
 58             }
 59         }
 60         return vis[t];
 61     }
 62     int dfs(int x, int a) {
 63         if (x == t || a == 0  ) return a;
 64         int flow = 0, f, len = g[x].size();
 65         for (int & i = cur[x] ; i < len ; i++) {
 66             node & e = nodes[g[x][i]];
 67             if (d[x] + 1 == d[e.to] && (f = dfs(e.to, min(a, e.cap - e.flow))) > 0 ) {
 68                 e.flow += f;
 69                 nodes[g[x][i] ^ 1].flow -= f;
 70                 flow += f;
 71                 a -= f;
 72                 if (a == 0) break;
 73             }
 74         }
 75         return flow;
 76     }
 77     int maxflow(int a, int b) {
 78         s = a;
 79         t = b;
 80         int flow = 0;
 81         while(bfs()) {
 82             memset(cur, 0, sizeof(cur));
 83             flow += dfs(s, INF) ;
 84         }
 85         return flow;
 86     }
 87     void print(int  u) {
 88         vis[u] = 1;
 89         for (int i = 0 ; i < (int)g[u].size() ; i++ ) {
 90             node & e = nodes[g[u][i]];
 91             if (!vis[e.to] && e.flow == 1 && e.from != st && e.to != ed) {
 92                 printf(" %d", e.to - ed / 2);
 93                 print(e.to - ed / 2);
 94             }
 95         }
 96     }
 97 } f;
 98 int main() {
 99     int n;
100     scanf("%d", &n);
101     int flow = 0, num = 0;
102     while(num - flow <= n ) {
103         num += 1;
104         f.add(st, num, 1);
105         f.add(num + ed / 2, ed, 1);
106         for (int i = 1 ; i < num ; i++) {
107             if ((int)sqrt(i + num) == sqrt(i + num)) f.add(i, num + ed / 2, 1);
108         }
109         flow += f.maxflow(st, ed);
110     }
111     num -= 1;
112     f.clearall(ed);
113     f.clearflow();
114     memset(f.vis, 0, sizeof(f.vis));
115     for (int i = 1 ; i <= num ; i++) {
116         f.add(0, i, 1);
117         f.add(i + ed / 2, ed, 1);
118         for (int j = 1 ; j < i ; j++) {
119             if ((int)sqrt(i + j) == sqrt(i + j)) f.add(j, i + ed / 2, 1);
120         }
121     }
122     f.maxflow(st, ed);
123     printf("%d\n", num);
124     memset(f.vis, 0, sizeof(f.vis)) ;
125     for (int i = 1 ; i <= num ; i++) {
126         if (!f.vis[i]) {
127             printf("%d", i);
128             f.print(i);
129             printf("\n");
130         }
131     }
132     return 0;
133 }

 




以上是关于P2765 魔术球问题(网络流24题)的主要内容,如果未能解决你的问题,请参考以下文章

P2765 魔术球问题

网络流24题魔术球问题(最大流)

网络流24题- 魔术球问题

网络流24题魔术球问题

「Luogu2765」[网络流24题] 魔术球问题

网络流24题魔术球问题(最小不相交路径覆盖)