题目大意:
有 \(n\) 个柱子,依次将若干个球放上去,要满足:
1.每次只能放在柱子的顶端
2.相邻两个球的编号之和必须为完全平方数。
问最多能放几个球?
\((1 \leq n \leq 55)\)
思路:
首先,答案一定不会很大,所以直接暴力一个一个加点,保留原流即可。
代码:
#include <bits/stdc++.h>using namespace std;#define REP(a, b, c) for (register int a = b, _n = c; a <= _n; ++a)
#define DREP(a, b, c) for (register int a = b, _n = c; a >= _n; --a)
#define FOR(a, b, c) for (register int a = b, _n = c; a < _n; ++a)
#define DFOR(a, b, c) for (register int a = b, _n = c; a > _n; --a)
#define EREP(a, b) for (register int a = first[b]; ~a; a = edge[a].nxt)
#define GREP(a, b) for (register int& a = cur[b]; ~a; a = edge[a].nxt)const int SIZE = 4005;
const int s = 0, t = 4000;int n;int now;int first[SIZE], ecnt;
struct Edge {int v, cap, flow, nxt;
} edge[SIZE * SIZE];
void Add_Edge (int u, int v, int cap) {edge[ecnt].v = v;edge[ecnt].cap = cap;edge[ecnt].flow = 0;edge[ecnt].nxt = first[u];first[u] = ecnt++;edge[ecnt].v = u;edge[ecnt].cap = 0;edge[ecnt].flow = 0;edge[ecnt].nxt = first[v];first[v] = ecnt++;
}int d[SIZE];
int cur[SIZE];bool BFS () {memset(d, 0, sizeof d);queue<int> Q;d[s] = 1;Q.push(s);while (!Q.empty()) {int u = Q.front();Q.pop();EREP (i, u) {Edge& e = edge[i];if (!d[e.v] && e.cap > e.flow)d[e.v] = d[u] + 1, Q.push(e.v);}}return d[t];
}
int DFS (int u, int a) {if (u == t || a == 0) return a;int flow = 0, f;GREP (i, u) {Edge& e = edge[i];if (d[e.v] == d[u] + 1 && (f = DFS(e.v, min(a, e.cap - e.flow))) > 0) {e.flow += f;edge[i ^ 1].flow -= f;flow += f;a -= f;}}return flow;
}
int MaxFlow () {int flow = 0;while (BFS()) {REP (i, 1, now)cur[i + n] = first[i + n], cur[i + 2000 + n] = first[i + 2000 + n];REP (i, 1, n)cur[i] = first[i];cur[s] = first[s], cur[t] = first[t];flow += DFS(s, 1e9);}return flow;
}int r[SIZE];
bool mark[SIZE];int main () {memset(first, -1, sizeof first);scanf ("%d", &n);Add_Edge(1, t, n);now = 1;while (1) {Add_Edge(s, now + n, 1);Add_Edge(now + n, 1, 1);REP (i, 1, now - 1) {int x = sqrt(i + now);if (x * x == i + now)Add_Edge(now + n, i + 2000 + n, 1);}Add_Edge(now + 2000 + n, t, 1);if (MaxFlow() == 0) {printf ("%d\n", now - 1);MaxFlow();FOR (i, 1, now) {EREP (j, i + n) {Edge& e = edge[j];if (e.flow == 1) {r[e.v] = i + n;if (e.v == 1) mark[i] = 1;break;}}}FOR (i, 1, now) if (mark[i]) {int x = i + n;while (x) {printf ("%d ", x - n);x = r[x + 2000];}puts("");}return 0;}++now;}
}