poj 1190 noi99 生日蛋糕
分析:经典剪枝。
我的稍微加了点剪枝的搜索连10000,3,这个数据都出不来结果,主要原因在于剪枝减去的太少了,而且从小到大搜索剪枝效果非常不好。后来参考了一下一个c++程序,非常快,16ms。
首先根据V=H*R*R,S=2*H*R可知2*V/S等于面积,这一面积是可能的最小面积。加上这个剪枝后非常快。
代码1:
var ans,maxh,maxr,n,m:longint; procedure dfs(v,h,r,deep,s:longint); var maxhh,maxvv,i,j:longint; begin if v<r*r*h*(m-deep+1) then exit; if v<0 then exit; if 2*r*h*(m-deep+1)+r*r>ans then exit; if s+r*r>ans then exit; if (v=0)and(deep<=m) then exit; if (deep>m)and(v>0) then exit; if (v=0)and(deep>m) then begin ans:=s+r*r; exit; end; maxhh:=maxh; maxvv:=maxr; if (h>0)and(r>0) then begin maxhh:=trunc(v/((r+1)*(r+1)*(m-deep+1))); maxvv:=trunc(sqrt(v/((h+1)*(m-deep+1)))); end; for j:=r+1 to maxvv do for i:=h+1 to maxhh do dfs(v-j*j*i,i,j,deep+1,s+2*i*j); end; begin readln(n,m); maxr:=trunc(sqrt(n/m)); maxh:=trunc(n/m); ans:=maxlongint; dfs(n,0,0,1,0); if ans=maxlongint then writeln(0) else writeln(ans); end.
代码2:
var mins,minv:array[0..20] of longint; n,m,ans,i:longint; function min(x,y:longint):longint; begin if x<y then exit(x); exit(y); end; procedure dfs(v,s,deep,r,h:longint); var i,j,hh:longint; begin if deep=0 then begin if (v=n)and(s<ans) then ans:=s; exit; end; if v+minv[deep]>n then exit; if s+mins[deep]>ans then exit; if 2*(n-v)/r+s>=ans then exit; for i:=r-1 downto deep do begin if deep=m then s:=i*i; hh:=min(trunc((n-v-minv[deep-1])/(i*i)),h-1); for j:=hh downto deep do dfs(v+i*i*j,s+2*i*j,deep-1,i,j); end; end; begin readln(n,m); for i:=1 to 20 do begin minv[i]:=minv[i-1]+i*i*i; mins[i]:=mins[i-1]+2*i*i; end; ans:=maxlongint; dfs(0,0,m,n+1,n+1); if ans=maxlongint then writeln(0) else writeln(ans); end.