问题描述:
假设有n根柱子,现要按下述规则在这n根柱子中依次放入编号为 1,2,3,4......的球。
(1)每次只能在某根柱子的最上面放球。
(2)在同一根柱子中,任何2个相邻球的编号之和为完全平方数。
试设计一个算法,计算出在n根柱子上最多能放多少个球。例如,在4 根柱子上最多可
放11个球。
´编程任务:
对于给定的n,计算在 n根柱子上最多能放多少个球。
´数据输入:
文件第1 行有 1个正整数n,表示柱子数。
´结果输出:
文件的第一行是球数。
数据规模
n<=60 保证答案小于1600
输入文件示例
4
输出文件示例
11
方案如下
1 8
2 7 9
3 6 10
4 5 11
每一行表示一个柱子上的球
网络流 最小路径覆盖
从1到1600枚举放的球数量。
将表示每个球的点拆分出入点和
从源点S到每个球入点连边,每个球出点到汇点连边,能放在一起的球之间连边(编号小的入点到编号大的出点)。
球数i-最大流答案m<=柱子数n时,可行。
/*by SilverN*/
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<vector>
#include<queue>
using namespace std;
const int INF=1e9;
const int mxn=;
int read(){
int x=,f=;char ch=getchar();
while(ch<'' || ch>''){if(ch=='-')f=-;ch=getchar();}
while(ch>='' && ch<=''){x=x*+ch-'';ch=getchar();}
return x*f;
}
struct edge{
int v,nxt,f;
}e[mxn*];
int hd[mxn],mct=;
void add_edge(int u,int v,int c){
e[++mct].v=v;e[mct].nxt=hd[u];e[mct].f=c;hd[u]=mct;return;
}
void insert(int u,int v,int c){
add_edge(u,v,c);add_edge(v,u,);return;
}
int n,m,S,T;
int d[mxn];
bool BFS(){
memset(d,,sizeof d);
queue<int>q;
q.push(S);
d[S]=;
while(!q.empty()){
int u=q.front();q.pop();
for(int i=hd[u];i;i=e[i].nxt){
int v=e[i].v;
if(e[i].f && !d[v]){
d[v]=d[u]+;
q.push(v);
}
}
}
return d[T];
}
int DFS(int u,int lim){
if(u==T)return lim;
int tmp,f=;
for(int i=hd[u];i;i=e[i].nxt){
int v=e[i].v;
if(d[v]==d[u]+ && e[i].f){
tmp=DFS(v,min(lim,e[i].f));
e[i].f-=tmp;
e[i^].f+=tmp;
f+=tmp;
lim-=tmp;
if(!lim)return f;
}
}
d[u]=;
return f;
}
int Dinic(){
int res=;
while(BFS())res+=DFS(S,INF);
return res;
}
int main(){
freopen("balla.in","r",stdin);
freopen("balla.out","w",stdout);
int i,j;
n=read();m=;
S=,T=;
for(i=;i<=;i++){
insert(S,i*-,);
insert(i*,T,);
for(j=;j<i;j++){
int t=sqrt(j+i);
if(t*t==j+i){
insert(j*-,i*,);
}
}
//
m+=Dinic();
if(i-m>n)break;
}
printf("%d\n",i-);
return ;
}