NOI 1999-3 生日蛋糕 解题报告

生日蛋糕

Birthday Cake

Cake.{pas|bas|c}

Cake.exe

7月17日是Mr.W的生日,ACM-THU为此要制作一个体积为Nπ的M层生日蛋糕,每层都是一个圆柱体。

设从下往上数第i(1<=i<=M)层蛋糕是半径为Ri,高度为Hi的圆柱。当i<M时,要求Ri>Ri+1且Hi>Hi+1。

由于要在蛋糕上抹奶油,为尽可能节约经费,我们希望蛋糕外表面(最下一层的下底面除外)的面积Q最小。

令Q= Sπ

请编程对给出的N和M,找出蛋糕的制作方案(适当的Ri和Hi的值),使S最小。

(除Q外,以上所有数据皆为正整数)

输入

有两行,第一行为N(N<=10000),表示待制作的蛋糕的体积为Nπ;第二行为M(M<=20),表示蛋糕的层数为M。

输出

仅一行,是一个正整数S(若无解则S=0)。

样例输入

100 2

样例输出

68

附:圆柱公式

体积V=πR2H

侧面积A’=2πRH

底面积A=πR2

搜索题。

但是,朴素的搜索面临大数据超时的危机-_-||

所以,剪枝是必要的:

  • 最优化剪枝

    • k层蛋糕的最小表面积可知(h,r都为整数)

    • 当前s可知

    • 那么,s+剩下层数最小表面积>=min最无需再往下搜了

  • 可行性剪枝

    • k层蛋糕的最小体积minv可知

    • k层蛋糕的最大体积maxv可知

    • 那么,剩下的体积v不在minv至maxv的范围内,即可停止搜索

最优化剪枝数据越大功力越强..^-^

于是便可以写出程序了.

下面是我的程序,并没有加所有的剪枝……不过AC足够了

//NOI1999-3: CAKE 
//2009-1-23: BY Ceeji 
//Type     : Search 
program noi1999_3; 
var n,m,i,j,k,l,q,max:longint; 
    mint,mins:array[0..20]of longint; 
procedure gettijimin; 
var i,j:longint; 
begin 
     j:=0;   mint[1]:=0; mint[0]:=0; 
     for i:=1 to m-1 do 
     begin 
          inc(j,i*i*i); 
          mint[i+1]:=j; 
     end; 
end; 
procedure getsmin; 
var i,j:longint; 
begin 
     j:=0;   mins[1]:=0; mins[0]:=0; 
     for i:=1 to m-1 do 
     begin 
          inc(j,2*i*i); 
          mins[i+1]:=j; 
     end; 
end; 
procedure sou(i,v,s,h,r:longint); // i: ceng shu; v:ti ji; s:mian ji; h:max {height}; 
var j,k,l,q:longint; 
begin 
     if (i=m+1)and(v=0)and(max>s)then 
     begin 
          max:=s; exit; 
     end; 
     if (i>m)or(v< =0) then exit; 
     for j:=h downto m-i+1 do 
     begin 
         for q:=r downto m-i+1 do 
         begin 
              if (i=m)and(q*q*j<>v)then continue; 
              if s+2*q*j+mins[m-i+1]>=max then continue; 
              if i<>1 then sou(i+1,v-q*q*j,s+2*q*j,j-1,q-1) 
                      else sou(i+1,v-q*q*j,s+2*q*j+q*q,j-1,q-1); 
         end; 
     end; 
end; 
begin 
     readln(n,m); 
     max:=100000000; 
     gettijimin; getsmin; 
     k:=mint[m]; 
     if n-k< =0 then begin writeln('0'); exit; end; 
     sou(1,n,0,trunc((n-k)/(m*m)),trunc(sqrt((n-k)/m))); 
     if max=100000000 then writeln('0') else writeln(max); 
end. 

本文版权遵循 CC BY-NC-SA 4.0发布,转载需附带本文链接。

当前页阅读量为: