题解:每次加入两个点,对于和为平方数的两个值所对应的点建边,反正网络流可以跑残量网络,所以就没有什么关系了……
代码如下:
#include<cmath> #include<queue> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define inf 0x3f3f3f3f using namespace std; int head[100010],next[100010],w[100010],v[100010],deep[100010]; int s,t,cnt; void init() { cnt=-1; memset(head,-1,sizeof(head)); memset(next,-1,sizeof(next)); } void add(int from,int to,int cost) { cnt++; next[cnt]=head[from]; w[cnt]=cost; v[cnt]=to; head[from]=cnt; } void add_edge(int from,int to,int cost) { add(from,to,cost); add(to,from,0); } int bfs(int s,int t) { queue<int> q; memset(deep,0,sizeof(deep)); deep[s]=1; q.push(s); while(!q.empty()) { int u=q.front(); q.pop(); for(int i=head[u]; i!=-1; i=next[i]) { if(!deep[v[i]]&&w[i]>0) { deep[v[i]]=deep[u]+1; q.push(v[i]); } } } if(!deep[t]) { return 0; } return 1; } int dfs(int u,int t,int dist) { if(u==t) { return dist; } for(int i=head[u]; i!=-1; i=next[i]) { if(w[i]&&(deep[u]+1==deep[v[i]])) { int di=dfs(v[i],t,min(w[i],dist)); if(di>0) { w[i]-=di; w[i^1]=di; return di; } } } return 0; } int dinic(int s,int t) { int ans=0; while(bfs(s,t)) { while(int d=dfs(s,t,inf)) { ans+=d; } } return ans; // } int id[11110],wid[11110],vis[11110]; void solve(int x,int &f) { int loc=wid[x]; vis[x]=1; for(int i=head[loc]; i!=-1; i=next[i]) { if(w[i]==1&&v[i]!=t) { solve(v[i]/2,f); } } if(f==1) { f=0; } else { putchar(' '); } printf("%d",x); } int main() { init(); int n; scanf("%d",&n); s=0; t=11110; int i,tmp=2,ans=0,tmp2=0; for(i=1; i-ans<=n+1; i++) { id[i]=tmp++; wid[i]=tmp++; add_edge(s,id[i],1); add_edge(wid[i],t,1); for(int j=1; j<i; j++) { int tmp1=sqrt(i+j); if(tmp1*tmp1==i+j) { add_edge(id[j],wid[i],1); } } ans+=dinic(s,t); } tmp2=i-2; printf("%d ",tmp2); for(int i=head[t]; i!=-1; i=next[i]) { if(w[i]==1&&!vis[v[i]/2]) { int f=1; solve(v[i]/2,f); puts(""); } } for(int i=1; i<=tmp2; i++) { if(!vis[i]) { printf("%d ",i); } } }