题目描述
假设有 n 根柱子,现要按下述规则在这 nn 根柱子中依次放入编号为 1,2,3,...的球“
-
每次只能在某根柱子的最上面放球。
-
同一根柱子中,任何 2 个相邻球的编号之和为完全平方数。
试设计一个算法,计算出在 n 根柱子上最多能放多少个球。例如,在 4 根柱子上最多可放 11 个球。
对于给定的 n,计算在 n 根柱子上最多能放多少个球。
输入格式
只有一行一个整数 n,代表柱子数。
输出格式
本题存在 Special Judge。
请将 n 根柱子上最多能放的球数以及相应的放置方案输出。
输出的第一行是球数。
接下来的 n 行,每行若干个整数,代表一根柱子上的球的编号,数字间用单个空格隔开。
输入输出样例
输入 #1复制
4
输出 #1复制
11 1 8 2 7 9 3 6 10 4 5 11
说明/提示
数据规模与约定
对于 100% 的数据,保证 1≤n≤55。
思路:网络流最小覆盖问题,我们将n根柱子所能放的最大点数m这个问题转化为最多只能用n条路径来覆盖m个点的问题。和普通最少路径覆盖不同,我们需要每添加一个点就在图里加上相应的边,并更新当前最小路径数,直到大于n的时候,上一个点数m即为答案。
#include<set>
#include<map>
#include<queue>
#include<vector>
#include<string>
#include<math.h>
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<functional>
using namespace std;
#define maxn 350500
#define ll long long
#define inf 1e9
int n,m,s,t,cnt=2,head[maxn];
int offset=3000,lv[maxn/10],nxt[maxn/10],cur[maxn];
struct edges{
int u;
int v;
int w;
int next;
}edges[maxn];
void add(int u,int v,int w){
edges[cnt].u=u;
edges[cnt].v=v;
edges[cnt].w=w;
edges[cnt].next=head[u];
head[u]=cnt++;
}
//lv是每个点的层数
bool bfs(){
memset(lv,-1,sizeof(lv));
memcpy(cur,head,sizeof(head)); //当前弧优化
lv[s]=0;
queue<int>q;
q.push(s);
while(!q.empty()){
int now=q.front();
q.pop();
for(int eg=head[now];eg;eg=edges[eg].next){
int to=edges[eg].v,val=edges[eg].w;
if(val>0 && lv[to]==-1)
lv[to]=lv[now]+1,q.push(to);
}
}
return lv[t]!=-1;
}
int dfs(int p=s,int flow=inf){
if(p==t)
return flow;
int mn=flow;
for(int eg=cur[p];eg;eg=edges[eg].next){
cur[p]=eg; //更新当前弧
int to=edges[eg].v,val=edges[eg].w;
if(val>0 && lv[to]==lv[p]+1){
ll c=dfs(to,min(val,mn));
mn-=c;
edges[eg].w-=c;
edges[eg^1].w+=c;
if(c) nxt[p]=to-offset;
}
}
return flow-mn;
}
ll dinic(){
ll maxFlow=0;
while(bfs())
maxFlow+=dfs();
return maxFlow;
}
bool jud(int x){
int y=sqrt(x);
return y*y==x;
}
int main(void){
int num=0;
scanf("%d",&n);
t=2*offset+1;
for(m=1;m<=2000;m++){
add(s,m,1);
add(m,s,0);
add(m+offset,t,1);
add(t,m+offset,0);
for(int i=1;i<m;i++)
if(jud(m+i))
add(i,m+offset,1),add(m+offset,i,0);
num+=dinic();
if(m-num>n) break;
}
m--;
cnt=2;
memset(nxt,0,sizeof(nxt));
memset(cur,0,sizeof(cur));
memset(head,0,sizeof(head));
for(int i=1;i<=m;i++){
add(s,i,1);
add(i,s,0);
add(i+offset,t,1);
add(t,i+offset,0);
for(int j=i+1;j<=m;j++)
if(jud(i+j))
add(i,j+offset,1),add(j+offset,i,0);
}
dinic();
printf("%d\n",m);
for(int eg=head[t];eg;eg=edges[eg].next){
if(edges[eg^1].w){
int now=edges[eg].v-offset;
printf("%d",now);
while(nxt[now]){
now=nxt[now];
printf(" %d",now);
}
printf("\n");
}
}
return 0;
}