裸奔 的傻瓜
在通往Ac的路上 蹒跚踱步

题目来源:http://acm.pku.edu.cn/JudgeOnline/problem?id=1190

唉 又没的饭吃了 水一下午的题。加速pku ranklist突破一千。
废话说完。来看看这道题目。其实我也是看了Sempr的代码。

这个题目就是说要建立m层的蛋糕 从下至上 满足半径逐渐变小,高度也逐渐变矮,是所有的体积满足条件但是表面积最小不包括最底层的底面
题目的关键就在于所有的数值都是整数,而且给出的体积N,M的数目也是有限的 所有基本可以枚举出每个具体的数值来验证符合条件否 当然这样显式的枚举肯定是不现实的 所以搜索+剪枝

搜索的步骤就是,从最低层开始,每一层从可能的最大半径一直枚举到最小可能半径,高度亦如此。一个参数表示层数,表示上一层的半径,高度,还是剩余体积,已有面积


 1 void dfs(int curP,int lastR,int lastH,int subV,int sumS)
 2 {
 3     if(curP==0)
 4     {
 5         if(subV==0&&minm>sumS)
 6         {
 7             minm=sumS;
 8         }
 9         return;
10     }
11
12     for(int i=lastR-1;i>=curP;i--)
13     {
14         for(int j=th;j>=curP;j--)
15         {
16             int sumV=i*i*j;
17             int s=i*j*2;
18             if(curP==m)
19             {
20                 s+=i*i;
21             }
22             dfs(curP-1,i,j,subV-sumV,sumS+s);
23         }
24     }
25 }


剪枝的方法有:
1)每一层的最短半径和最短高度肯定它距顶层的层数。因为下一层至少比上一层多半径和高度各多1.所有就可以求得剩下层最小的体积和最小的面积。对比现有的体积和面积已经求得的最小面积。
2)对于枚举出的一个半径后,结合剩余体积可以求得他最大可能的高度。
3)对于枚举半径和高度,结合剩余体积和当前面积,可以估算结果的最小面积有最小可能。

剪枝后:


 1 void dfs(int curP,int lastR,int lastH,int subV,int sumS)
 2 {
 3     if(subV<sum[curP]||sumS+d[curP]>=minm) return;
 4     if(curP==0)
 5     {
 6         if(subV==0&&minm>sumS)
 7         {
 8             minm=sumS;
 9         }
10         return;
11     }
12
13     for(int i=lastR-1;i>=curP;i--)
14     {
15         int th=(int)((subV-sum[curP-1])/(double)(i*i));
16         th=th<(lastH-1)?th:(lastH-1);
17         for(int j=th;j>=curP;j--)
18         {
19             if (2 * (subV - i * i * j) / i + sumS + 2 * i * j >= minm) continue;
20             int sumV=i*i*j;
21             int s=i*j*2;
22             if(curP==m)
23             {
24                 s+=i*i;
25             }
26             dfs(curP-1,i,j,subV-sumV,sumS+s);
27         }
28     }

结合和原来的剪枝,发现自己没有考虑到面积的范围。

posted on 2008-10-26 18:44  Lyt  阅读(861)  评论(0编辑  收藏  举报