标签:sample lang memory one min start 整数 out size
Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 18225 | Accepted: 6486 |
Description
Input
Output
Sample Input
100 2
Sample Output
68
Hint
题目分析: 以前做过一次, 但是智障的我还是忘了, 这次写废了很大的劲儿, 发现还是有很多东西自己想不到, 这道题是典型的DFS,需要剪枝否则会TLE, 前两个剪枝很好想, 但是第三个剪枝不好想( 自己干想, 看题解一下就明白了, 这是病, 得治 )。 当前的解加上剩余最优解如果大于最优解就剪枝。 有很多细节需要注意, 比如说需要一个minv保存前i层的最小体积,(因为从上到下不管是r 还是 h 都是严格单调递增的!!!)当dep == m 的时候将 tmp 初始化为r * r , 回溯的时候就应该当初始化为 0..................类似于此的细节还有很多............. 直接附上代码, 代码的注释已经讲得很详细了.......
#include <iostream> #include <cstring> #include <cstdio> #include <string> #include <algorithm> #include <set> #define INF 0x3fffffff using namespace std; int ans; // 保存临时最优解 int minv[21]; // 前 i 块蛋糕的最小体积( 从上到下 ) int tmp; // 保存当前表面积 int n, m; void Init() { memset( minv, 0, sizeof( minv ) ); for( int i = 1; i <= 20; i++ ) { minv[i] = minv[i-1] + i * i * i; } } void dfs( int v, int dep, int R, int H ) { // 剩余体积, 当前深度, 当前的半径, 当前的高 if( dep == 0 ) { if( v == 0 && ans > tmp ) { // 只有当体积正好为 0 的时候才能更新ans ( 就是说正好满足n 体积 && m 层 ) ans = tmp; } return; } if( v - minv[dep-1] < 0 || tmp >= ans || 2 * v / R + tmp >= ans ) return; // 如果剩余体积小于最小体积( 蛋糕不能到 m 层 ) 或者 当前解已经比最优解大 // 或者当前解 + 剩余部分的最优解比最优解大 , 剪枝, 神剪枝 for( int r = R - 1; r >= dep; r-- ) { // 因为这是从底向上遍历的, 所以r and h 都不会小于 dep int Hm = min( H - 1, ( v - minv[dep-1] ) / r / r ); for( int h = Hm; h >= dep; h-- ) { if( v - r * r * h >= 0 ) { if( dep == m ) tmp = r * r; // 如果深度为 m 的话则表面积为最下面一块的上表面, 这样以后只需要增添侧表面积就可以了 tmp += 2 * r * h; dfs( v - r * r * h, dep - 1, r, h ); tmp -= 2 * r * h; // 回溯 if( dep == m ) tmp = 0; } } } return; } int main() { Init(); // 建立一个储存前 i 层最小体积的 数组 while( cin >> n >> m ) { ans = INF; dfs( n, m, n + 1, n + 1 ); // 后面的 两个 n + 1 只是保证足够大 cout << ans << endl; } return 0; }
看来自己的做过的题还是要重做, 多想, 然后就是果然题量不能说明一切, 思想才是最重要的 ,只有思想搞上来了才不会沦为码农, 多看书, 多培养自己的思维, 代码量固然要够, 但是能够安安静静的看书的时间大部分都在大学中, 所以适当的调整方向, 人一我十, 人十我万!!!
标签:sample lang memory one min start 整数 out size
原文地址:http://www.cnblogs.com/FriskyPuppy/p/6048588.html