「网络流24题」魔术球问题

传送门:>Here<

题意:有N根柱子,并且有连续编号的小球依次放入。要求后来的小球只能放在某根柱子最上面的小球上面,并且必须满足这两个小球的编号之和为完全平方数。求最多能放几个小球?

思路分析

真是好题~

由于N的范围不到60,所以我们可以采用非常暴力的做法。

把问题反过来考虑,如果有N个球,最少用几个柱子?考虑DAG的最小路径覆盖——将能够放在一起的(即和为完全平方数)的小球之间连有向边(小的连到大的),这样的一张图的最小路径覆盖也就是需要的最少的柱子。因此问题就转化为了最小路径覆盖问题——拆点+最大流。

因此我们只需要枚举小球的数量,每一次把新来的小球拆成两个,分别连源点和汇点,并且扫一遍连完全平方数。然后每一次做一遍Dinic(千万注意flow要清零),判断是否够N根柱子。如果大于N,则跳出。去除这一次多余的边重新建图跑Dinic,输出方案即可

现在有一个问题,为什么柱子的需求量与小球数量成正比?其实很简单,新加进去一个球并没有可能性让柱子的数量减少。

Code

典型的细节题:注意在统计的时候由于编号是偶数,每次+2,而不是*2!

另外,去除最后多余的边是个问题。我们可以考虑重新弄一张邻接表,每一次如果成功就把所有边赋值一遍。注意first随时都会修改,所以所有点的first都需要更新。最后在记录sec的时候要记得-1,分清奇偶性。

/*By DennyQi*/
#include <cstdio>
#include <queue>
#include <cstring>
#include <algorithm>
#define  r  read()
#define  Max(a,b)  (((a)>(b)) ? (a) : (b))
#define  Min(a,b)  (((a)<(b)) ? (a) : (b))
using namespace std;
typedef long long ll;
const int MAXN = 100010;
const int MAXM = 300010;
const int INF = 1061109567;
inline int read(){
    int x = 0; int w = 1; register int c = getchar();
    while(c ^ ‘-‘ && (c < ‘0‘ || c > ‘9‘)) c = getchar();
    if(c == ‘-‘) w = -1, c = getchar();
    while(c >= ‘0‘ && c <= ‘9‘) x = (x << 3) +(x << 1) + c - ‘0‘, c = getchar(); return x * w;
}
int P,N,S,T,x,y,match;
int first[MAXM*2],nxt[MAXM*2],to[MAXM*2],cap[MAXM*2],flow[MAXM*2],num_edge=-1;
int _first[MAXM*2],_nxt[MAXM*2],_to[MAXM*2],_cap[MAXM*2],_flow[MAXM*2],last=-1;
int level[MAXN],cur[MAXN],pre[MAXN],sec[MAXN];
queue <int> q;
inline void add(int u, int v, int c, int f){
    to[++num_edge] = v;
    cap[num_edge] = c;
    flow[num_edge] = f;
    nxt[num_edge] = first[u];
    first[u] = num_edge;
}
inline void AddEdge(int u, int v){
    add(u*2, v*2+1, 1, 0);
    add(v*2+1, u*2, 0, 0);
}
inline bool BFS(){
    memset(level, 0, sizeof(level));
    while(!q.empty()) q.pop();
    q.push(S);
    level[S] = 1;
    int u,v;
    while(!q.empty()){
        u = q.front(); q.pop();
        for(int i = first[u]; i != -1; i = nxt[i]){
            v = to[i];
            if(!level[v] && cap[i]-flow[i] > 0){
                level[v] = level[u] + 1;
                q.push(v);
            }
        }
    }
    return level[T] != 0;
}
int DFS(int u, int a){
    if(u == T || a == 0) return a;
    int ans = 0, v, _f;
    for(int& i = cur[u]; i != -1; i = nxt[i]){
        v = to[i];
        if(level[u]+1 == level[v] && cap[i]-flow[i] > 0){
            _f = DFS(v, Min(a, cap[i]-flow[i]));
            ans += _f, a -= _f;
            flow[i] += _f, flow[i^1] -= _f;
            if(a == 0) break;
        }
    }
    return ans;
}
inline void Dinic(){
    match = 0;
    while(BFS()){
        for(int i = S; i <= T; ++i) cur[i] = first[i];
        match += DFS(S, INF);
    }
    match = N - match;
}
int main(){
    P=r;
    S = 0, T = 12345;
    memset(first,-1,sizeof(first));
    for(N = 1; ; ++N){
        last = num_edge;
        memset(flow, 0, sizeof(flow));
        for(int i = 1; i < N; ++i){
            if(i*i - N >= N) break;
            if(i*i > N){
                AddEdge(i*i-N, N);
            }
        }
        add(S, N*2, 1, 0), add(N*2, S, 0, 0);
        add(N*2+1, T, 1, 0), add(T, N*2+1, 0, 0);
        Dinic();
        if(match > P){
            --N;
            break;
        }
        for(int i = 0; i <= num_edge; ++i){
            _nxt[i] = nxt[i];
            _cap[i] = cap[i];
            _flow[i] = flow[i];
            _to[i] = to[i];
        }
        for(int i = 0; i <= N*2+4; ++i){
            _first[i] = first[i];
        }
        _first[T] = first[T];
    }
    printf("%d\n", N);
    for(int i = 2; i <= 2*N; i += 2){
        for(int j = _first[i]; j != -1; j = _nxt[j]){
            if(_cap[j]-_flow[j]==0 && _cap[j]==1){
                pre[_to[j]-1] = i;
                sec[i] = _to[j]-1;
            }
        }
    }
    for(int i = 2; i <= 2*N; i += 2){
        if(pre[i] == 0){
            int u = i;
            while(sec[u] != 0){
                printf("%d ", u/2);
                u = sec[u];
            }
            printf("%d\n", u/2);
        }
    }
    return 0;
}

原文地址:https://www.cnblogs.com/qixingzhi/p/9419319.html

时间: 2024-11-05 20:30:18

「网络流24题」魔术球问题的相关文章

LiberOJ 6003. 「网络流 24 题」魔术球 贪心或者最小路径覆盖

6003. 「网络流 24 题」魔术球 内存限制:256 MiB时间限制:1000 ms标准输入输出 题目类型:传统评测方式:Special Judge 上传者: 匿名 提交提交记录统计讨论测试数据 题目描述 假设有 n nn 根柱子,现要按下述规则在这 n nn 根柱子中依次放入编号为 1,2,3,4,? 1, 2, 3, 4, \cdots1,2,3,4,? 的球. 每次只能在某根柱子的最上面放球. 在同一根柱子中,任何 2 22 个相邻球的编号之和为完全平方数. 试设计一个算法,计算出在 

[loj #6003]「网络流 24 题」魔术球 二分图最小路径覆盖,网络流

#6003. 「网络流 24 题」魔术球 内存限制:256 MiB时间限制:1000 ms标准输入输出 题目类型:传统评测方式:Special Judge 上传者: 匿名 提交提交记录统计讨论测试数据 题目描述 假设有 n nn 根柱子,现要按下述规则在这 n nn 根柱子中依次放入编号为 1,2,3,4,? 1, 2, 3, 4, \cdots1,2,3,4,? 的球. 每次只能在某根柱子的最上面放球. 在同一根柱子中,任何 2 22 个相邻球的编号之和为完全平方数. 试设计一个算法,计算出在

「网络流24题」 题目列表

「网络流24题」 题目列表 序号 题目标题 模型 题解 1 飞行员配对方案问题 二分图最大匹配 <1> 2 太空飞行计划问题 最大权闭合子图 <2> 3 最小路径覆盖问题 二分图最小路径覆盖 <3> 4 魔术球问题 <4> 5 圆桌问题 <5> 6 最长递增子序列问题 <6> 7 试题库问题 <7> 8 机器人路径规划问题 <8> 9 方格取数问题 二分图最大点权独立集 <9> 10 餐巾计划问题

【网络流24题】魔术球问题

P1226 - [网络流24题]魔术球问题 Description 假设有n根柱子,现要按下述规则在这n根柱子中依次放入编号为 1,2,3,4......的球. (1)每次只能在某根柱子的最上面放球. (2)在同一根柱子中,任何2个相邻球的编号之和为完全平方数. 试设计一个算法,计算出在n根柱子上最多能放多少个球.例如,在4 根柱子上最多可 放11个球. ′编程任务: 对于给定的n,计算在 n根柱子上最多能放多少个球. Input 第1 行有 1个正整数n,表示柱子数. Output 第一行是球

LibreOJ #6001. 「网络流 24 题」太空飞行计划 最大权闭合图

#6001. 「网络流 24 题」太空飞行计划 内存限制:256 MiB时间限制:1000 ms标准输入输出 题目类型:传统评测方式:Special Judge 上传者: 匿名 提交提交记录统计讨论测试数据 题目描述 W 教授正在为国家航天中心计划一系列的太空飞行.每次太空飞行可进行一系列商业性实验而获取利润.现已确定了一个可供选择的实验集合 E={E1,E2,?,Em} E = \{ E_1, E_2, \cdots, E_m \}E={E?1??,E?2??,?,E?m??},和进行这些实验

LiberOJ #6013. 「网络流 24 题」负载平衡 最小费用最大流 供应平衡问题

#6013. 「网络流 24 题」负载平衡 内存限制:256 MiB时间限制:1000 ms标准输入输出 题目类型:传统评测方式:文本比较 上传者: 匿名 提交提交记录统计讨论测试数据 题目描述 G 公司有 n nn 个沿铁路运输线环形排列的仓库,每个仓库存储的货物数量不等.如何用最少搬运量可以使 n nn 个仓库的库存数量相同.搬运货物时,只能在相邻的仓库之间搬运. 输入格式 文件的第 1 11 行中有 1 11 个正整数 n nn,表示有 n nn 个仓库.第 2 22 行中有 n nn 个

LiberOJ #6000. 「网络流 24 题」搭配飞行员 最大匹配

#6000. 「网络流 24 题」搭配飞行员 内存限制:256 MiB时间限制:1000 ms标准输入输出 题目类型:传统评测方式:文本比较 上传者: 匿名 提交提交记录统计讨论测试数据 题目描述 飞行大队有若干个来自各地的驾驶员,专门驾驶一种型号的飞机,这种飞机每架有两个驾驶员,需一个正驾驶员和一个副驾驶员.由于种种原因,例如相互配合的问题,有些驾驶员不能在同一架飞机上飞行,问如何搭配驾驶员才能使出航的飞机最多. 因为驾驶工作分工严格,两个正驾驶员或两个副驾驶员都不能同机飞行. 输入格式 第一

LiberOJ #6002. 「网络流 24 题」最小路径覆盖

#6002. 「网络流 24 题」最小路径覆盖 内存限制:256 MiB时间限制:1000 ms标准输入输出 题目类型:传统评测方式:Special Judge 上传者: 匿名 提交提交记录统计讨论测试数据 题目描述 给定有向图 G=(V,E) G = (V, E)G=(V,E).设 P PP 是 G GG 的一个简单路(顶点不相交)的集合.如果 V VV 中每个顶点恰好在 P PP 的一条路上,则称 P PP 是 G GG 的一个路径覆盖.P PP 中路径可以从 V VV 的任何一个顶点开始,

LiberOJ #6007. 「网络流 24 题」方格取数 最小割 最大点权独立集 最大流

#6007. 「网络流 24 题」方格取数 内存限制:256 MiB时间限制:1000 ms标准输入输出 题目类型:传统评测方式:文本比较 上传者: 匿名 提交提交记录统计讨论测试数据 题目描述 在一个有 m×n m \times nm×n 个方格的棋盘中,每个方格中有一个正整数. 现要从方格中取数,使任意 2 22 个数所在方格没有公共边,且取出的数的总和最大.试设计一个满足要求的取数算法. 输入格式 文件第 1 11 行有 2 22 个正整数 m mm 和 n nn,分别表示棋盘的行数和列数