先来说下怎么建模。其实就是经典的拆点模型
1.将一个数拆成两个点集x0,x1。
2.将x0连接至源点,x1连接至汇点
3.如果对于一个数i<j i+j == 某个数的平方,就在两个点集之间找到对应的点连一条边
要是想直接求解有点麻烦,所以可以枚举答案。每次新添加进来一个数,然后直接在残量网络上跑最大流就行,一旦匹配数达到n-1,也就是刚好完成了n个柱子,此时跳出就行
#include <iostream>
#include <cstdio>
#include <bits/stdc++.h>
using namespace std;
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
using namespace std;
const int INF=0x3f3f3f3f;
const int MAXN=20000;//点数的最大值
const int MAXM=20500;//边数的最大值
struct Node
{
int from,to,next;
int cap;
}edge[MAXM];
int tol;
int dep[MAXN];//dep为点的层次
int head[MAXN];
int T = 10000;
int m = 5000;
int n,s,ans;
void init()
{
tol=0;
memset(head,-1,sizeof(head));
}
void addedge(int u,int v,int w)//第一条变下标必须为偶数
{
edge[tol].from=u;
edge[tol].to=v;
edge[tol].cap=w;
edge[tol].next=head[u];
head[u]=tol++;
edge[tol].from=v;
edge[tol].to=u;
edge[tol].cap=0;
edge[tol].next=head[v];
head[v]=tol++;
}
bool bfs()
{
queue<int> q;
memset(dep,-1,sizeof(dep));
dep[0] = 0;
q.push(0);
while(!q.empty())
{
int now = q.front();
q.pop();
for(int i = head[now];i != -1 ;i = edge[i].next)
{
int v = edge[i].to;
if(dep[v] == -1 && edge[i].cap)
{
dep[v] = dep[now] +1;
q.push(v);
}
}
}
if(dep[T] == -1) return false;
return true;
}
int dfs(int u,int f)
{
if(u==T)return f;
int used=0;
for(int i=head[u];i;i=edge[i].next)
{
if(!edge[i].cap||dep[edge[i].to]!=dep[u]+1)continue;
int w=f-used;
w=dfs(edge[i].to,min(w,edge[i].cap));
edge[i].cap-=w;
edge[i^1].cap+=w;
used+=w;
if(used==f)return f;
}
if(!used)dep[u]=-1;
return used;
}
void dinic()
{
while(bfs())
{
ans -= dfs(0,INF);
}
}
void print_all_edge()
{
for(int i = 0;i < tol ;i += 2)
{
printf("%d -> %d cap: % d,flow: %d\n",edge[i].from,edge[i].to,edge[i].cap);
}
}
inline bool getint(int &num)
{
char in;bool IsN=false;
in=getchar();
if(in==EOF || in == '\n') return false;
while(in!='-'&&(in<'0'||in>'9')) in=getchar();
if(in=='-'){ IsN=true;num=0;}
else num=in-'0';
while(in=getchar(),in>='0'&&in<='9'){
num*=10,num+=in-'0';
}
if(IsN) num=-num;
if(in == '\n') return false;
return true;
}
bool check(int x)
{
if(sqrt(x) == (int) sqrt(x)) return 1;
else return 0;
}
int main()
{
getint(n);
init();
while(1)
{
ans++,s++;
for(int i = 1;i<s;i++)
{
if(sqrt(i+s) == (int)sqrt(i + s))
{
addedge(i,s+m,1);
}
}
addedge(0,s,1);
addedge(s+m,T,1);
dinic();
printf("%d\n",ans);
if(ans > n) break;
}
printf("%d\n",s-1);
return 0;
}