ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

AcWing 168. 生日蛋糕

2021-08-18 19:31:51  阅读:204  来源: 互联网

标签:剪枝 limits int sum cfrac depth 168 生日蛋糕 AcWing


原题链接:AcWing 168. 生日蛋糕

设当前体积是\(v,h、r\)分别记录每层的高度和半径,由于整个蛋糕的上表面面积等于最大蛋糕的圆面积,所以枚举到最大一层的时候直接加上即可。

  1. 优化搜索顺序:搜数量小的分支,可以从蛋糕最下边一层开始搜索,因为最下边一层占体积最大,然后对于枚举半径\(R\)和高度\(H\),肯定是先枚举半径\(R\),因为它对体积的贡献是平方级别的。

  2. 上下界剪枝:在第\(depth\)层时,对于\(R\)与\(H\)可以求一个范围:

    枚举\(R \in [depth, \,\, min( \lfloor \sqrt{N - v} \rfloor, \,\, r[depth + 1] - 1)]\),

    枚举\(H \in [depth, \,\, min( \lfloor cfrac{(N - v)}{R^2} \rfloor, \,\, h[depth + 1] - 1)]\)

  3. 可行性剪枝:
    预处理出每一层的最小体积和表面积,显然,第\(1 到 i\)层的\(r\)分别取\(1, 2, 3, ..., i\)即可,高度也分别取\(1, 2, 3, ..., i\)。那么当当前\(v\)加\(1\)到\(depth - 1\)层的\(minv\)大于\(N\)那么直接返回。

  4. 最优性剪枝\(1\):
    如果当前表面积\(s\)加上\(1\)到\(depth - 1\)层的\(mins\),那么就剪枝。

  5. 最优性剪枝\(2\):
    利用\(h\)和\(r\)数组,\(1\)到\(depth-1\)层的体积可以表示为 \(n - v = \sum\limits_{k = 1}^{depth-1} h[k] * r[k]^2\),1到depth - 1层的表面积可以表示为\(2 * \sum\limits_{k=1}^{depth - 1} h[k]*r[k]\)。

    利用放缩法,\(2 * \sum\limits_{k=1}^{depth - 1} h[k]*r[k] = \cfrac{2}{r[depth]} * \sum\limits_{k = 1}^{depth - 1} h[k] * r[k] * r[depth] \geq \cfrac{2}{r[depth]} * \sum\limits_{k = 1}^{depth - 1} h[k] * r[k]^2 \geq \cfrac{2(n - v)}{r[depth]}\),所以当\(\cfrac{2(n - v)}{r[depth]} + s\)大于已经搜到的答案时,可以剪枝。

// Problem: 生日蛋糕
// Contest: AcWing
// URL: https://www.acwing.com/problem/content/170/
// Memory Limit: 10 MB
// Time Limit: 1000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>

using namespace std;

const int N = 25, INF = 1E9;

int n, m;
int R[N], H[N];
int res = INF;
int minv[N], mins[N];

void dfs(int u, int v, int s) {
	if (v + minv[u] > n) return;
	if (s + mins[u] >= res) return;
	if (s + 2 * (n - v) / R[u + 1] >= res) return;
	
	//说明已经从上往下搜到了最后一层
	if (!u) {
		if (v == n) res = s;
		return;
	}
	
	for (int r = min(R[u + 1] - 1, (int)sqrt(n - v)); r >= u; r--) {
		for (int h = min(H[u + 1] - 1, (n - v) / r / r); h >= u; h--) {
			int t = 0;
			if (u == m) t = r * r;
			R[u] = r, H[u] = h;
			
			dfs(u - 1, v + r * r * h, s + 2 * r * h + t);
		}
	}
}

int main() { 
	cin >> n >> m;
	
	for (int i = 1; i <= m; i++) {
		minv[i] = minv[i - 1] + i * i * i;
		mins[i] = mins[i - 1] + i * i * 2;
	}
	
	R[m + 1] = H[m + 1] = INF;
	
	dfs(m, 0, 0);
	
	if (res == INF) res = 0;
	cout << res << endl;
	
    return 0;
}

标签:剪枝,limits,int,sum,cfrac,depth,168,生日蛋糕,AcWing
来源: https://www.cnblogs.com/ZhengLijie/p/15154547.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有