洛谷 P1731 [NOI1999]生日蛋糕 && POJ 1190 生日蛋糕

题目传送门(洛谷)  OR 题目传送门(POJ)

解题思路:

一道搜索题,暴力思路比较容易想出来,但是这道题不剪枝肯定会TLE.所以这道题难点在于如何剪枝.

1.如果当前状态答案已经比我们以前某个状态求出来的答案还要大,那么我们就没有必要搜下去,直接return.

2.如果有某个状态,在这之后假设所有答案都是最优,还比我们当前已经求出来的最小值大,那么哇哦们也没有必要搜下去,return;

3.如果在某个状态之后,所有层蛋糕都用最大体积,也无法达到答案体积,那么也没必要搜,return.

以上三条剪枝对于这道题来说已经够了.

如果还想再优化一下,那么可以求出每层蛋糕当前R和H范围,在范围之间枚举,这样做也会使程序快一点,对于这道题来说,没必要//就因为写这个剪枝花了我1个半小时,最后还没写对,直接去掉这条剪枝,AC.

AC代码:

 1 #include<cstdio>
 2 #include<cmath>
 3 #include<iostream>
 4 #include<math.h> 
 5 
 6 using namespace std;
 7 
 8 int n,m,ans = 0x7f7f7f7f,_min[25],oo[25];
 9 
10 int find_max(int nn,int h,int r) {
11     int vv = 0;
12     for(int i = 1;i <= m - nn + 1; i++) 
13         vv += (h - i) * (r - i) * (r - i);
14     return vv;
15 }
16 
17 inline void dfs(int deep,int h,int r,int v,int len) {
18     if(deep == m + 1) {
19         if(v != 0) return ;
20         ans = min(ans,len);
21         return ;
22     }
23     if(v < 0) return ;
24     int u = len;
25     u += _min[deep];
26     if(ans < u) return ;
27     u = find_max(deep,h,r);
28     if(v > u && deep != 1) return;
29     for(int i = 1;i < r; i++) {
30         for(int j = 1;j < h; j++) {
31             if(i * i * j > v) continue;
32             if(a[deep][i][j]) continue;
33             if(deep == 1) len = i * i;
34             dfs(deep + 1,j,i,v - j * i * i,len + 2 * j * i);
35         }
36     }
37 }
38 
39 inline void special() {
40     for(int i = 1;i <= sqrt(n); i++) {
41         if(n % (i * i) != 0) continue;
42         int j = n / (i * i);
43         int len = i * i + i * 2 * j;
44         ans = min(ans,len);
45     }
46 }
47 
48 int main()
49 {
50     scanf("%d%d",&n,&m);
51     for(int p = m;p >= 1; p--) 
52         _min[p] = _min[p+1] + (m - p + 1) * 2 * (m - p + 1);
53     if(m == 1) special();
54     else dfs(1,25,25,n,0);
55     if(ans == 0x7f7f7f7f) printf("0");
56     else printf("%d",ans);
57     return 0;
58 }

 

posted @ 2019-09-09 22:58  Mr^Simon  阅读(194)  评论(0编辑  收藏  举报