心如止水
Je n'ai pas le temps
posts - 400,comments - 130,trackbacks - 0

对于这一题首先可以想到一些明显的剪枝策略:

1、 从下往上数第iRiHi至少为m-i+1,因为要至少保证上面几层可以有的选择;

2、 比已出解大,剪枝;

3、 假设第i层半径为Ri、高为Hi,则i+1层半径最多为Ri-1,高最多为Hi-1,考虑极端的情况,那就是剩余m-i层半径都为Ri-1,高都为Hi-1,如果这样还达不到体积n,需要剪枝;

4、 考虑最小的情况,从i+1层到m层全部为1,如果这样还大于体积n,需要剪枝;

5、 1层的情况,极端情况为高是1,此时半径最大sqrt(n);半径为1,高最大n,这是搜索的边界

6、 假设前i层体积为nowv,表面积为nows,第i层半径为Ri,则如果2*(n-nowv)/rr+nows>=已出解,需要剪枝。这一点有空将给出证明。

 

以下是我的代码:

#include<stdio.h>
#include
<math.h>
long n,m,ans=200000000;
void dfs(long dep,long nowv,long nows,long rr,long hh)
{// 前dep层蛋糕体积为nowv 表面积为nows 第dep层半径rr 高度hh 
    if(dep>=m)
    
{
       
if(nowv==n&&nows<ans)
         ans
=nows;
       
return;
    }

    
if(nowv+(rr-1)*(rr-1)*(hh-1)*(m-dep)<n) return;// 每层最大都达不到体积 
    if(nowv+m-dep>n) return;// 每层最小都超过体积 
    if(2*(n-nowv)/rr+nows>=ans) return;// 不等式放缩法剪枝 
    long i,j;
    
for(i=rr-1;i>=m-dep;i--)
      
for(j=hh-1;j>=m-dep;j--)
        
if(nows+2*i*j<ans)// 比已出解小 
          dfs(dep+1,nowv+i*i*j,nows+2*i*j,i,j);
}

int main()
{
    FILE 
*fin,*fout;
    
long i,j;
    fin
=fopen("cake.in","r");
    fscanf(fin,
"%ld%ld",&n,&m);
    fclose(fin);
// Read In
    for(i=m;i<=sqrt(n);i++)
      
for(j=m;j<=n;j++)
       dfs(
1,i*i*j,i*i+2*i*j,i,j);
    fout
=fopen("cake.out","w");
    fprintf(fout,
"%ld\n",ans);
    fclose(fout);
return 0;
}

posted on 2010-01-06 19:44 lee1r 阅读(1164) 评论(0)  编辑 收藏 引用 所属分类: 题目分类:搜索

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理