• AcWing 168. 生日蛋糕


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

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

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

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

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

      枚举(H in [depth, \,\, min( lfloor cfrac{(N - v)}{R^2} floor, \,\, 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 = sumlimits_{k = 1}^{depth-1} h[k] * r[k]^2),1到depth - 1层的表面积可以表示为(2 * sumlimits_{k=1}^{depth - 1} h[k]*r[k])

      利用放缩法,(2 * sumlimits_{k=1}^{depth - 1} h[k]*r[k] = cfrac{2}{r[depth]} * sumlimits_{k = 1}^{depth - 1} h[k] * r[k] * r[depth] geq cfrac{2}{r[depth]} * sumlimits_{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;
    }
    
  • 相关阅读:
    Web API 依赖注入与扩展
    ASP.NET Web API 简介
    经典SQL语句大全_主外键_约束
    自学MVC看这里——全网最全ASP.NET MVC 教程汇总
    正则表达式的汉字匹配
    Sql Server 删除所有表
    细说ASP.NET Forms身份认证
    NET Web的身份认证
    C#百万数据查询超时问题
    nodejs 命令行交互
  • 原文地址:https://www.cnblogs.com/ZhengLijie/p/15154547.html
Copyright © 2020-2023  润新知