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


    题目描述

    «问题描述:

    假设有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


    巩固一下网络流(之前也没怎么练XD

    这道题可以发现对于每个球就两种状态,要么前面放一个能和他凑平方数的球,要么就独占一个柱子的开头

    其实换种思路,每个球屁股后面要么是空的,要么是连上了一个能和他凑的数

    结果你会发现这就变成了二分图匹配问题,只要匹配上的数量尽可能多,我们就尽可能的利用了柱子

    对X具体连线方法:

    x'看作是X的头,x看作是X的尾

    S向x连一条容量为1的边

    x‘向T连一条容量为1的边

    对于所有y<x且x+y为平方数的边,连从y到x'的容量唯一的边

    每次跑最大流

    而动态的做法呢,我么可以一边加球,一边求当前所需的最小柱子(不停的跑dinic

    但是这题可以打表(+2,+4,+4,+6,+6,+8,+8。。。。。)

    以上

     1 #include<bits/stdc++.h>
     2 #define N 400000
     3 #define INF (1<<30)
     4 using namespace std;
     5 int n,ans;
     6 int h[100000],nxt[N],flow[N],to[N],etop;
     7 int nex[N];
     8 void add(int u,int v,int w){
     9     to[etop]=v,nxt[etop]=h[u],flow[etop]=w,h[u]=etop++;
    10     to[etop]=u,nxt[etop]=h[v],flow[etop]=0,h[v]=etop++;
    11 }
    12 int S,T;
    13 void getans(){
    14     ans=1;
    15     int la=2;
    16     for(int i=2;i<=n;i++){
    17         if(i&1)ans+=la;
    18         else{
    19             ans+=la;
    20             la+=2;
    21         }
    22     }
    23 }
    24 int lev[N];
    25 queue<int>q;
    26 bool bfs(){
    27     memset(lev,-1,sizeof(lev));
    28     lev[S]=0;
    29     q.push(S);
    30     while(!q.empty()){
    31         int u=q.front();q.pop();
    32         for(int k=h[u];~k;k=nxt[k]){
    33             int v=to[k];
    34             if(lev[v]==-1&&flow[k]>0){
    35                 lev[v]=lev[u]+1;
    36                 q.push(v);
    37             }
    38         }
    39     }
    40     return lev[T]!=-1;
    41 }
    42 int dfs(int u,int t,int left){
    43     if(u==t)return left;
    44     for(int k=h[u];~k;k=nxt[k]){
    45         int v=to[k];
    46         if(flow[k]>0&&lev[v]==lev[u]+1){
    47             int d=dfs(v,t,min(left,flow[k]));
    48             if(d>0){
    49                 flow[k]-=d;
    50                 flow[k^1]+=d;
    51                 if(v!=t)nex[u>>1]=v>>1;
    52                 return d;
    53             }
    54         }
    55     }
    56     return 0;
    57 }
    58 int dinic(){
    59     int fl=0;
    60     while(bfs()){
    61         int f;
    62         while((f=dfs(S,T,INF))>0)fl+=f;
    63     }
    64     return fl;
    65 }
    66 int in[2000];
    67 int main(){
    68     scanf("%d",&n);
    69     getans();
    70     memset(h,-1,sizeof(h));
    71     memset(nex,-1,sizeof(nex));
    72     S=0,T=10010;
    73     for(int i=1;i<=ans;i++){
    74         add(S,i<<1,1);add(i<<1|1,T,1);
    75         for(int j=sqrt(i)+1;j*j<(i<<1);j++)add((j*j-i)<<1,i<<1|1,1);
    76     }
    77     dinic();
    78     cout<<ans<<endl;
    79     for(int i=1;i<=ans;i++)
    80     if(nex[i]!=-1)in[nex[i]]++;
    81     while(!q.empty())q.pop();
    82     for(int i=1;i<=ans;i++)if(in[i]==0)q.push(i);
    83     while(!q.empty()){
    84         int u=q.front();
    85         q.pop();
    86         cout<<u;u=nex[u];
    87         while(u!=-1){
    88             cout<<' '<<u;
    89             u=nex[u];
    90         }
    91         cout<<endl;
    92     }
    93 }
    View Code

  • 相关阅读:
    14-定时器
    13-JS中的面向对象
    12-关于DOM操作的相关案例
    11-DOM介绍
    10-关于DOM的事件操作
    09-伪数组 arguments
    08-函数
    07-常用内置对象
    06-流程控制
    05-数据类型转换
  • 原文地址:https://www.cnblogs.com/2017SSY/p/10837258.html
Copyright © 2020-2023  润新知