又是一个神奇的建图题,建图(Van)♂全不会啊
大体就是我们一个一个的把球放进来,每放进来一个,我们就求出当前的最小路径覆盖数(当前顶点数-最大流),直到最小路径覆盖数({>})柱子数。此时的球的编号(-1)就是第一问的答案。第二问就是求每一条路径,顺着推下来就好了
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#include<cmath>
using namespace std;
struct zzz{
int t,len,nex;
}e[100010<<1]; int head[20010],tot=1;
void add(int x,int y,int z){
e[++tot].t=y;
e[tot].len=z;
e[tot].nex=head[x];
head[x]=tot;
}
int s=0,t=20000,vis[20010],pre[20010];
bool bfs(){
memset(vis,0,sizeof(vis));
queue <int> q; q.push(s); vis[s]=1;
while(!q.empty()){
int k=q.front(); q.pop();
for(int i=head[k];i;i=e[i].nex){
int to=e[i].t;
if(vis[to]||!e[i].len) continue;
q.push(to); vis[to]=vis[k]+1;
if(to==t) return 1;
}
}
return vis[t];
}
int dfs(int now,int flow){
if(now==t||!flow) return flow;
int rest=0,fl;
for(int i=head[now];i;i=e[i].nex){
int to=e[i].t;
if(vis[to]==vis[now]+1&&(fl=dfs(to,min(flow,e[i].len)))){
e[i].len-=fl, e[i^1].len+=fl, rest+=fl;
if(rest==flow) return rest;
}
}
if(rest<flow) vis[now]=0;
return rest;
}
int dinic(){
int ans=0;
while(bfs()) ans+=dfs(s,2147483647);
return ans;
}
int read(){
int k=0; char c=getchar();
for(;c<'0'||c>'9';) c=getchar();
for(;c>='0'&&c<='9';c=getchar())
k=(k<<3)+(k<<1)+c-48;
return k;
}
bool jl[20010]; int next[20010];
int main(){
int n=read(),cnt=0,num=0;
while(cnt<=n){
num++; cnt++;
for(int i=1;i<num;i++)
if(sqrt(i+num)==(int)sqrt(i+num))
add(i,num+10000,1),add(num+10000,i,0);
add(s,num,1); add(num,s,0);
add(num+10000,t,1); add(t,num+10000,0);
cnt-=dinic();
}
printf("%d
",--num);
for(int i=1;i<=num;i++){
for(int j=head[i];j;j=e[j].nex){
if(!e[j].len){
next[i]=e[j].t-10000;
break;
}
}
}
for(int i=1;i<=num;i++){
if(jl[i]) continue;
int x=i;
while(x!=-10000){
jl[x]=1; printf("%d ",x);
x=next[x];
}
printf("
");
}
return 0;
}