P2765 魔术球问题 (网络流)

题意:n根柱子 把编号1,2,3....的球依次插到柱子上去

   需要满足相邻的两个球编号加起来为完全平方数 n < 55

题解:网络流24(23)题里的 

   但是一直不知道怎么建图  或者说建图的意义

   一般都要套路拆点 我的理解就是实际问题背景每个点是需要双向边的 但是网络流算法要建反向边 所以就拆点防止重边 意义更明确

   这个题的话把小球拆点就表示 一个放前面 一个放后面的情况 然后按题意建图 跑最大流

   我最开始以为一条增广路代表一根柱子 其实不是 这里柱子的意义更抽象

   模拟一下程序后发现 在依次加球的过程中 最大流跑通表示的是这个球可以直接接在当前安排方式的后面

   如果跑不通 就要新开柱子了 同时跑新的最大流也能保证反悔操作

#include <bits/stdc++.h>
using namespace std;

int n, cnt, p, num, s, t, maxflow;

struct node {
    int to, nex, val;
}E[200005];
int head[4005];
int cur[4005];

void addedge(int x, int y, int va) {
    E[++cnt].to = y; E[cnt].nex = head[x]; E[cnt].val = va; head[x] = cnt;
    E[++cnt].to = x; E[cnt].nex = head[y]; E[cnt].val = 0; head[y] = cnt;
}

int dep[4005];
int to[4005];
int inque[4005];
bool bfs() {
    for(int i = 0; i <= num * 2 + 2; i++) cur[i] = head[i], dep[i] = 0x3f3f3f3f, inque[i] = 0;
    dep[s] = 0;
    queue<int> que;
    que.push(s);
    inque[s] = 1;

    while(!que.empty()) {
        int u = que.front();
        que.pop();

        for(int i = head[u]; i; i = E[i].nex) {
            int v = E[i].to;
            if(E[i].val > 0 && dep[v] > dep[u] + 1) {
                dep[v] = dep[u] + 1;
                if(!inque[v]) {
                    inque[v] = 1;
                    que.push(v);
                }
            }
        }
    }
    if(dep[t] != 0x3f3f3f3f) return true;
    return false;
}

int vis;
int dfs(int x, int flow) {
    if(x == t) {
        vis = 1;
        maxflow += flow;
        return flow;
    }

    int rflow = 0;
    int used = 0;
    for(int i = cur[x]; i; i = E[i].nex) {
        cur[x] = i;
        int v = E[i].to;
        if(E[i].val > 0 && dep[v] == dep[x] + 1) {
            if(rflow = dfs(v, min(flow - used, E[i].val))) {
                to[x / 2] = v / 2;
                used += rflow;
                E[i].val -= rflow;
                E[i ^ 1].val += rflow;
                if(used == flow) break;
            }
        }
    }
    return used;
}

void dinic() {
    maxflow = 0;
    while(bfs()) {
        vis = 1;
        while(vis) {
            vis = 0;
            dfs(s, 100000000);
        }
    }
}

int ans[60];

int main() {
    p = num = 0;
    cnt = 1;
    scanf("%d", &n);
    s = 0; t = 1;
    while(p <= n) {
        num++;
        addedge(s, num << 1, 1);
        addedge(num << 1 | 1, t, 1);
        for(int i = sqrt(num) + 1; i * i < 2 * num; i++) {
            addedge((i * i - num) << 1, num << 1 | 1, 1);
        }

        dinic();
        if(!maxflow) {
            ans[++p] = num;
        }
    }
    printf("%d
", num - 1);
    
    for(int i = 1; i <= n; i++) {
        printf("%d", ans[i]);
        for(int j = ans[i]; to[j]; j = to[j]) printf(" %d", to[j]);
        puts("");
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/lwqq3/p/11150204.html