POJ - 1190 生日蛋糕 dfs+剪枝

时间:2023-03-09 02:17:24
POJ - 1190 生日蛋糕 dfs+剪枝

思路:说一下最重要的剪枝,如果当前已经使用了v的体积,为了让剩下的表面积最小,最好的办法就是让R尽量大,因为V = πR
2H,A' = 2πRH,A' = V / R * 2 ,最大的R一定是取当前的r,所以得到剩下最小表面积就是(n-v)/r*2,如果(n-v)/r*2 + s >= ans,ans是当前得到的最小表面积,直接剪枝。

AC代码

#include <cstdio>
#include <cmath>
#include <cctype>
#include <algorithm>
#include <cstring>
#include <utility>
#include <string>
#include <iostream>
#include <map>
#include <set>
#include <vector>
#include <queue>
#include <stack>
using namespace std;
#pragma comment(linker, "/STACK:1024000000,1024000000")
#define eps 1e-10
#define inf 0x3f3f3f3f
#define PI pair<int, int>
typedef long long LL;
const int maxn = 1e4 + 5;
int ans, n, m;
void dfs(int r, int h, int lev, int v, int s) { //v-已经使用的体积 s-已经出现的表面积
	if(v > n || (lev == m && v != n)) return;
	if(lev == m && v == n) {
		ans = min(ans, s);
		return;
	}
	if(s + (n-v)/r*2 >= ans) {
		return; //剪枝
	}
	for(int i = r-1; i >= m-lev; --i)
		for(int j = h-1; j >= m-lev; --j) {
			dfs(i, j, lev+1, v + i*i*j, s + 2*i*j);
		}
}

int main() {
	while(scanf("%d%d", &n, &m) == 2) {
		ans = inf;
		//枚举最底层
		for(int i = 25; i > 0; --i)
			for(int j = 25; j > 0; --j) {
				if(n-i*i*j >= 0) {
					dfs(i, j, 1, i*i*j, i*i + 2*i*j);
				}
			}
		if(ans == inf) printf("-1\n");
		else printf("%d\n", ans);
	}

	return 0;
}

如有不当之处欢迎指出!