又是一个神奇的建图题,建图\(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\n",--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("\n"); } return 0; }