【网络流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

 

posted @ 2019-05-09 11:00  瞬闪影  阅读(228)  评论(0编辑  收藏  举报