魔术球问题

题目大意:

(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;
    }
}

原文地址:https://www.cnblogs.com/ZPAYAUR/p/11298523.html