网络流二十四题之魔术球问题

P2765 魔术球问题

题目描述

«问题描述:

假设有n根柱子,现要按下述规则在这n根柱子中依次放入编号为1,2,3,...的球。

(1)每次只能在某根柱子的最上面放球。

(2)在同一根柱子中,任何2个相邻球的编号之和为完全平方数。

试设计一个算法,计算出在n根柱子上最多能放多少个球。例如,在4 根柱子上最多可放11 个球。

«编程任务:

对于给定的n,计算在n根柱子上最多能放多少个球。

输入输出格式

输入格式:

第1 行有1个正整数n,表示柱子数。

输出格式:

程序运行结束时,将n 根柱子上最多能放的球数以及相应的放置方案输出。文件的第一行是球数。接下来的n行,每行是一根柱子上的球的编号。

输入输出样例

输入样例#1: 复制

4

输出样例#1: 复制

11
1 8
2 7 9
3 6 10
4 5 11

说明

感谢 @PhoenixEclipse 提供spj

4<=n<=55

魔术球问题
这个题目是一个网络流问题,虽然看起来一点也不像

给定柱子数n(最小路径覆盖数)以及放球条件(建图条件),求最多有多少个球(最多有多少个点可以满足这个最小的路径覆盖数

思路:
二分图匹配。
本质上和那个最小覆盖路径差不多。
就是把每一个球拆成两个部分,一个入点一个出点。
然后每次新加一个球先让他连接源点和汇点,然后判断他可不可以与另一个点连接,可以就不需要新占用一根柱子,不可以就占用一根柱子。
这个点如何拆呢,题解用的i>>1,i>>1|1,我觉这样子拆分很好,不过比较难想。

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <queue>
#include <cmath>
#include <iostream>
#include <vector>
#define inf 0x3f3f3f3f
using namespace std;
const int  maxn = 1e5 + 10;
int s = 1e5 + 1, t = 1e5 + 2,n;
struct node
{
    int from, to, cap, flow;
    node(int from=0,int to=0,int cap=0,int flow=0):from(from),to(to),cap(cap),flow(flow){}
};
vector<node>e;
vector<int>G[maxn];
int level[maxn], iter[maxn], head[maxn];
void add(int u,int v,int c)
{
    e.push_back(node(u, v, c, 0));
    e.push_back(node(v, u, 0, 0));
    int len = e.size();
    G[u].push_back(len - 2);
    G[v].push_back(len - 1);
}

void bfs(int s)
{
    memset(level, -1, sizeof(level));
    queue<int>que;
    que.push(s);
    level[s] = 0;
    while(!que.empty())
    {
        int u = que.front(); que.pop();
        for(int i=0;i<G[u].size();i++)
        {
            node &now = e[G[u][i]];
            if(level[now.to]<0&&now.cap>now.flow)
            {
                level[now.to] = level[u] + 1;
                que.push(now.to);
            }
        }
    }
}
int to[maxn];

int dfs(int u,int v,int f)
{
    if (u == v) return f;
    for(int &i=iter[u];i<G[u].size();i++)
    {
        node &now = e[G[u][i]];
        if(now.cap>now.flow&&level[now.to]>level[u])
        {
            int d = dfs(now.to, v, min(f, now.cap - now.flow));
            if(d>0)
            {
                //printf("%d %d %d\n", d, now.to>>1, u>>1);
                if (u == s) to[0] = now.to >> 1;
                if (now.to == t) to[u >> 1] = -1;
                else to[u >> 1] = now.to >> 1;
                now.flow += d;
                e[G[u][i] ^ 1].flow -= d;
                return d;
            }
        }
    }
    return 0;
}

int max_flow()
{
    int flow = 0;
    while(1)
    {
        bfs(s);
        if (level[t] < 0) return flow;
        memset(iter, 0, sizeof(iter));
        int f;
        while ((f = dfs(s, t, inf)) > 0) flow += f;
    }
}

int main()
{
    cin >> n;
    int num = 0, cnt = 0;
    memset(to, -1, sizeof(to));
    while(num<=n)
    {
        cnt++;
        add(s, cnt << 1, 1);
        add(cnt << 1 | 1, t, 1);
        for(int i=sqrt(cnt)+1;i*i<(cnt<<1);i++)//这个是去查找有没有可以和第cnt这个球连起来的球
            //前面的i的初始化是因为这个可能被连的数一定会>0的
            //后面的限制是 i*i-now<now  所以i*i<2*cnt=cnt<<1,意思就是这个数一定在cnt之前
        {
            add((i*i - cnt) << 1, cnt << 1 | 1, 1);
        }
        int ans = max_flow();
        if(!ans)
        {
            head[++num] = cnt;
        }
    }
    printf("%d\n", cnt - 1);
    for(int i=1;i<=n;i++)
    {
        int now = head[i];
        printf("%d ", now);
        while(to[now]!=-1)
        {
            now = to[now];
            printf("%d ", now);
        }
        printf("\n");
    }
    return 0;
}

原文地址:https://www.cnblogs.com/EchoZQN/p/10740252.html

时间: 2024-08-28 13:36:43

网络流二十四题之魔术球问题的相关文章

网络流二十四题

网络流二十四题 网络流是个好东西,希望我也会. 网络流?\(orz\ zsy!!!!!\) P2766 最长不下降子序列问题 考虑我们是如何\(dp\)这个\(LIS\)的. 我们是倒着推,设置\(dp(i)\)代表以\(i\)为起点的\(LIS\)是多少.转移太显然了 \[ dp(i)=max\{dp(j)\}+1,data[i]\le data[j] \] 想一想一个合法的\(LIS\)方案代表着什么,代表着它是由这个式子一个一个推出来的. 考虑一个数字只能用一次,那么我们直接拆成两个点\(

网络流二十四题之餐巾计划问题

题目传送门 这题的思路我觉得five20巨佬讲的已经非常清晰了,所以就推荐一下他的题解,我就只放代码了 //It is made by HolseLee on 7th Feb 2018 //Luogu.org P1251 #include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<iostream> #include<queue> #inc

网络流二十四题 分配问题

分配问题 题目描述 有 nn 件工作要分配给 nn 个人做.第 ii 个人做第 jj 件工作产生的效益为 c_{ij}cij? .试设计一个将 nn 件工作分配给 nn 个人做的分配方案,使产生的总效益最大. 输入输出格式 输入格式: 文件的第 11 行有 11 个正整数 nn ,表示有 nn 件工作要分配给 nn 个人做. 接下来的 nn 行中,每行有 nn 个整数 c_{ij}cij? ??,表示第 ii 个人做第 jj 件工作产生的效益为 c_{ij}cij? . 输出格式: 两行分别输出

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

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

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 个相邻球的编号之和为完全平方数. 试设计一个算法,计算出在 

【网络流24题】魔术球

LOJ 6003 [网络流24题]魔术球 题面 [题目描述] 假设有 n 根柱子,现要按下述规则在这 n 根柱子中依次放入编号为 1,2,3,4,? 的球. 每次只能在某根柱子的最上面放球. 在同一根柱子中,任何 2个相邻球的编号之和为完全平方数. 试设计一个算法,计算出在 n 根柱子上最多能放多少个球. [输入格式] 文件第 1 行有 1 个正整数 n(n <= 50) ,表示柱子数. [输出格式] 第一行是球数.接下来的 n 行,每行是一根柱子上的球的编号. 题解 能放的球数非常少,所以我们

【网络流24题】魔术球问题(最小不相交路径覆盖)

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

[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 个相邻球的编号之和为完全平方数. 试设计一个算法,计算出在

二十四式太极拳

.起势 左脚开立 两臂前举屈膝按掌 二.左右野马分鬃 1.左野马分鬃 稍右转体 收脚抱球 转体上步 弓步分手 2.右野马分鬃 坐撇脚 收脚抱球 转体上步 弓步分手 3.左野马分鬃 坐撇脚 收脚抱球 转体上步 弓步分手 三.白鹤亮翅 稍右转体 跟步抱球 坐转体 虚步分手 四.左右搂膝拗步 1.左搂膝拗步 转体摆臂 摆臂收脚 上步屈肘 弓步搂推 2.右搂膝拗步 坐撇脚 摆臂收脚 上步屈肘 弓步搂推 3.左搂膝拗步 坐撇脚 摆臂收脚 上步屈肘 弓步搂推 五.手挥琵琶 跟步展臂 坐引手 虚步合手 六.左