这题……讲道理我没看懂。
不过我看懂题解的代码是在干嘛了qwq
题解是zhaoyifan的题解
然后……我来讲讲这个题解好了。
题解把值为i的球拆成了两个,一个编号是i*2,一个编号是i*2+1。
为什么编号要这么编呢?因为统计编号的时候好统计qwq
然后从起点向i*2连一条边,从i*2+1到终点连一条边。
然后对于能够跟他凑成完全平方数的连边。
然后跑最大流,如果发现这个球不能串进原来的柱子上,也就是说最大流没有变化,那么就新加一条柱子。
当柱子数超过n的时候就退出循环开始统计。
大概……是这样。
#include<cstdio> #include<cstring> #include<algorithm> #include<cstdlib> #include<cctype> #include<queue> #include<cmath> #define maxn 200020 using namespace std; inline long long read(){ long long num=0,f=1; char ch=getchar(); while(!isdigit(ch)){ if(ch==‘-‘) f=-1; ch=getchar(); } while(isdigit(ch)){ num=num*10+ch-‘0‘; ch=getchar(); } return num*f; } bool calc(int x){ return sqrt(x)*sqrt(x)==x; } inline int count(int i){ return i&1?i+1:i-1; } struct Edge{ int next,to,val; }edge[maxn*5]; int head[maxn],num; inline void addedge(int from,int to,int val){ edge[++num]=(Edge){head[from],to,val}; head[from]=num; } inline void add(int from,int to,int val){ addedge(from,to,val); addedge(to,from,0); } bool vis[maxn]; int dfn[maxn]; int list[maxn]; int road[maxn]; int Start,End; bool bfs(){ memset(vis,0,sizeof(vis)); queue<int>q; q.push(Start); vis[Start]=1; dfn[Start]=1; while(!q.empty()){ int from=q.front(); q.pop(); for(int i=head[from];i;i=edge[i].next){ int to=edge[i].to; if(vis[to]||edge[i].val==0) continue; vis[to]=1; q.push(to); dfn[to]=dfn[from]+1; } } return vis[End]; } int dfs(int x,int val){ if(x==End||val==0) return val; int flow=0; vis[x]=1; for(int &i=list[x];i;i=edge[i].next){ int to=edge[i].to; if(vis[to]||edge[i].val==0||dfn[to]!=dfn[x]+1) continue; int now=dfs(to,min(val,edge[i].val)); edge[i].val-=now; edge[count(i)].val+=now; flow+=now; val-=now; road[x>>1]=to>>1; if(val<=0) break; } if(flow!=val) dfn[x]=-1; return flow; } int maxflow(){ int ans=0; while(bfs()){ memset(vis,0,sizeof(vis)); for(int i=Start;i<=End;++i) list[i]=head[i]; int now=dfs(Start,0x7fffffff); if(!now) break; ans+=now; } return ans; } int tot; int cnt; int New[maxn]; int main(){ End=50003; int n=read(); while(tot<=n){ cnt++; add(Start,cnt*2,1); add(cnt*2+1,End,1); for(int i=sqrt(cnt)+1;i*i<cnt*2;++i) add((i*i-cnt)*2,cnt*2+1,1); int ans=maxflow(); if(ans==0) New[++tot]=cnt; } printf("%d\n",--cnt); memset(vis,0,sizeof(vis)); for(int i=1;i<=n;++i){ if(vis[New[i]]) continue; int x=New[i]; vis[x]=1; while((x!=End>>1)&&x){ printf("%d ",x); x=road[x]; vis[x]=1; } printf("\n"); } return 0; }
原文地址:https://www.cnblogs.com/cellular-automaton/p/8206506.html
时间: 2024-10-08 05:13:00