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题)的主要内容,如果未能解决你的问题,请参考以下文章