4 5 11
【问题分析】
枚举答案转化为判定性问题,然后最小路径覆盖,可以转化成二分图最大匹配,从而用最大流解决。
【建模方法】
枚举答案A,在图中建立节点1..A。如果对于i<j有i+j为一个完全平方数,连接一条有向边(i,j)。该图是有向无环图,求最小路径覆盖。如果刚好满足最小路径覆盖数等于N,那么A是一个可行解,在所有可行解中找到最大的A,即为最优解。
具体方法可以顺序枚举A的值,当最小路径覆盖数刚好大于N时终止,A-1就是最优解。
【建模分析】
由于是顺序放球,每根柱子上的球满足这样的特征,即下面的球编号小于上面球的编号。抽象成图论,把每个球看作一个顶点,就是编号较小的顶点向编号较大的顶点连接边,条件是两个球可以相邻,即编号之和为完全平方数。每根柱子看做一条路径,N根柱子要覆盖掉所有点,一个解就是一个路径覆盖。
这题给的数据因为没有special judge,但有很多种方案,所以过不了,但是最小路径覆盖数是一样的,所以也就不管了。
打完这题后我懂得了一个重要的思想:一个图加点后的最小路径覆盖数一定是非递减的。
代码:
type arr=array[1..100000] of record x,y,z,next,p:longint; end; const maxn=10000; var i,j,s,t,e,a,n,ans:longint; side:arr; d,last:array[0..maxn+1] of longint; v:array[0..maxn+1] of boolean; function bfs:boolean; var head,tail,u,i:longint; state:array[1..maxn+2] of longint; begin head:=0; tail:=1; state[1]:=s; fillchar(d,sizeof(d),0); d[s]:=1; repeat inc(head); u:=state[head]; i:=last[u]; while i>0 do with side[i] do begin if (z>0)and(d[y]=0) then begin d[y]:=d[u]+1; inc(tail); state[tail]:=y; if y=t then exit(true); end; i:=next; end; until head>=tail; bfs:=false; end; function min(x,y:longint):longint; begin if x<y then exit(x) else exit(y); end; function dfs(x,maxf:longint):longint; var f,i,ret:longint; begin if x=t then exit(maxf); ret:=0; i:=last[x]; while i>0 do with side[i] do begin if (z>0)and(d[y]=d[x]+1) then begin f:=dfs(y,min(maxf-ret,z)); ret:=ret+f; dec(z,f); inc(side[p].z,f); if ret=maxf then exit(ret); end; i:=next; end; dfs:=ret; end; procedure dfs1(x:longint); var i:longint; begin v[x]:=false; i:=last[x]; while i>0 do with side[i] do begin if (z=0)and(side[p].z=1)and(v[maxn+1-y])and(y>a) then begin write(maxn+1-y,' '); dfs1(maxn+1-y); break; end; i:=next; end; end; procedure insert(x,y:longint); begin inc(e); side[e].x:=x; side[e].y:=y; side[e].z:=1; side[e].p:=e+1; side[e].next:=last[x]; last[x]:=e; inc(e); side[e].x:=y; side[e].y:=x; side[e].z:=0; side[e].p:=e-1; side[e].next:=last[y]; last[y]:=e; end; begin //assign(input,'ball.in'); //assign(output,'ball.out'); reset(input); rewrite(output); readln(n); a:=n; for i:=1 to a-1 do for j:=i+1 to a do if sqr(trunc(sqrt(i+j)))=i+j then insert(i,maxn-j+1); s:=0; t:=maxn+1; for i:=1 to a do begin insert(s,i); insert(maxn-i+1,t); end; while true do begin while bfs do ans:=ans+dfs(s,maxlongint); if a-ans>n then break; inc(a); for i:=1 to a-1 do if sqr(trunc(sqrt(i+a)))=i+a then insert(i,maxn-a+1); insert(s,a); insert(maxn-a+1,t); end; writeln(a-1); dec(a); fillchar(v,sizeof(v),true); for i:=1 to a do if v[i] then begin write(i,' '); dfs1(i); writeln; end; close(input); close(output); end.