题目大意:
有 (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
", 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;
}
}