洛谷 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 }