题意:中文题(lrj黑书上好像有这道题)
思路:这个题的建图还真的是挺有意思的,我们把一个球拆成2个点a,b。 然后让a点连S点,b点连T点,如果有两个数的加和为平方数,那我们就用第一个数的a点连向第二个数的b点,这样就有一条流直接流向汇点T
代码:(顺便get了怎么打印路径,赋学习传送门)
#include <bits/stdc++.h> using namespace std; typedef long long LL; inline LL read() { LL x=0,f=1;char ch=getchar(); while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } struct Edge{ int next,to,f; }; struct Dinic { int s,t; Edge e[1000010]; int cnt=2,head[1000010]={0}; int dis[1000010]={0}; Dinic (){} void init(int _s,int _t) { cnt=2; s=_s,t=_t; memset(head,0,sizeof(head)); } void addedge(int u,int v,int f) { e[cnt]={head[u],v,f}; head[u]=cnt++; e[cnt]={head[v],u,0}; head[v]=cnt++; } bool bfs() { memset(dis,0,sizeof(dis)); dis[s]=1; queue<int> q; q.push(s); while(!q.empty()) { int u=q.front(); q.pop(); for(int i=head[u];i;i=e[i].next) { int v=e[i].to; if(!dis[v]&&e[i].f>0) { dis[v]=dis[u]+1; q.push(v); } } } return dis[t]!=0; } int dfs(int u,int flow) { if(u==t||flow==0) return flow; int flow_sum=0; for(int i=head[u];i;i=e[i].next) { int v=e[i].to,f=e[i].f; if(dis[v]!=dis[u]+1||f==0) continue; int temp=dfs(v,min(flow-flow_sum,f)); e[i].f-=temp; e[i^1].f+=temp; flow_sum+=temp; if(flow_sum>=flow) break; } if(!flow_sum) dis[u]=-1; return flow_sum; } int maxflow() { int ans=0; while(bfs()) { while(int temp=dfs(s,0x7fffffff)) ans+=temp; } return ans; } }DC; int vis[20050]; int main() { int n=read(); int ball; int cnt=0; int s=0,t=20000; DC.init(s,t); for(cnt=0,ball=1;cnt<=n;cnt++){ if(cnt){ ball++; } for(;;ball++){ DC.addedge(s,ball,1); DC.addedge(ball+10000,t,1); for(int i=1;i<ball;i++){ if(sqrt(ball+i)==(int)sqrt(ball+i)){ DC.addedge(i,ball+10000,1); } } int as=DC.maxflow(); if(!as)break; } } printf("%d",ball-1); for(int i=1;i<=ball-1;i++){ if(vis[i])continue; vis[i]=true;cout<<endl<<i<<' '; int k=i; while(true){ bool ok=false; for(int i=DC.head[k];i;i=DC.e[i].next){ int v=DC.e[i].to,f=DC.e[i].f; if(v>10000&&f==0){ cout<<v-10000<<' '; vis[v-10000]=true; k=v-10000;ok=true; break; } } if(!ok)break; } } return 0; }