905 AlvinZH的奇幻猜想——三次方

思路

中等题。题意简单,题目说得简单,把一个数分成多个立方数的和,问最小立方数个数。

脑子转得快的马上想到贪心,从最近的三次方数往下减,反正有1^3在最后撑着保证减完。不好意思这是错的,因为1,27,64,125...等立方数之间并不是倍数关系,不能构成贪心策略。举个反例:96=64+8+8+8+8=64+27+1+1+1+1+1,答案明显是5,而贪心会算到7。

既然不是贪心,那就是DP了,没毛病。先讲一下常规做法吧,是这样想的:相当于把一个数化成几份,求最小划分的份数,那么把所求数看成背包的总体积,每个立方数的值看作每个物品的体积,价值都看做1,问题就转化为完全背包(因为每个立方数可以取多次)恰好装满求最小的价值,仔细想想。

所以,套一下完全背包的板子吧,但是,这里的一个问题是完全背包装满,这怎么办呢(可能由于本题可以保证装满这个问题不怎么显眼)。举一反三,假设有可能装不满,怎么办?这个问题初始化dp数组时就可以解决。以下方法对于01背包同样适用:

  • 普通01背包or完全背包:初始化为0;
  • 01背包or完全背包装满求价值最小:初始化为一个大数值如 \(INF\) (0x3f3f3f3f);
  • 01背包or完全背包装满求价值最大:初始化为一个小数值如 \(-INF\) (-0x3f3f3f3f);

为什么呢?对于本题,初始化为大数值,如果没装满,最后dp[n]会依然是INF,因为我们每次比较取的都是较小值。第二次练习赛的G题就是01背包装满求最大价值,初始化为最小值即可。(熬夜写了这么多,希望大家看得到QAQ)

这题还有另外的解法,那就是类似打表,先把所有数的最小立方个数通过迭代计算得到,然后 \(O(1)\) 时间取得答案。具体可见队列迭代的参考代码二以及for循环迭代的参考代码三。其实这里面也是有DP的思想,因为每次迭代会用到之前的结果,对于多组数据来讲,同样可以节省时间。简单易懂,可以学习一下。

分析

对于完全背包直接解法,时间复杂度为 \(O(V*∑(V/wi))\) 。

迭代的话复杂度差不了多少,由于多组数据的原因,迭代打表运行总时间显得更短些,不纠结这个。

扩展:完全背包装满问题:HDU 1114。

参考代码一:完全背包装满求最小价值

//
// Created by AlvinZH on 2017/10/24.
// Copyright (c) AlvinZH. All rights reserved.
// #include <cstdio>
#include <cstring>
#define INF 0x3f3f3f3f
#define MaxSize 1000005 int weight[105];
int ans[MaxSize]; int main()
{
for (int i = 1; i < 105; ++i)
weight[i] = i * i * i; int n;
while(~scanf("%d", &n))
{
for (int i = 0; i <= n; ++i)//初始化为最大值
ans[i] = INF; ans[0] = 0; for (int i = 0; i < 105; ++i) {
for (int j = weight[i]; j <= n; ++j) {
if(ans[j] > ans[j-weight[i]] + 1)
ans[j] = ans[j-weight[i]] + 1;
}
}
if(ans[n] == n) printf("Oh NO!\n");
else printf("%d\n", ans[n]);
}
} /*
* 完全背包恰好装满问题,求最小值。
*/

参考代码二:队列迭代

//
// Created by AlvinZH on 2017/10/24.
// Copyright (c) AlvinZH. All rights reserved.
// #include <cstdio>
#include <cstring>
#include <queue>
#define INF 0x3f3f3f3f
#define MaxSize 1000005
using namespace std; int weight[105];
int ans[MaxSize];
queue<int> Q; void init()
{
memset(ans, INF, sizeof(ans));
for (int i = 1; i < 105; ++i)
weight[i] = i * i * i; for (int i = 1; i <= 100; ++i) {
ans[weight[i]] = 1;
Q.push(weight[i]);
}
while(!Q.empty())
{
int w = Q.front();
Q.pop();
for (int i = 1; i <= 100; ++i) {
int num = weight[i] + w;
if(num > 1000000) break;
if(ans[num] < INF) continue;
ans[num] = ans[w] + 1;
Q.push(num);
}
}
} int main()
{
init();
int n;
while(~scanf("%d", &n))
{
if(ans[n] == n) printf("Oh NO!\n");
else printf("%d\n", ans[n]);
}
}
/*
* 思路:直接宽搜,把最开始的数扔进队列,反复用队列中的数去更新没更新的数就行了,注意数组别越界。
*/

参考代码三:for循环迭代

/*
Author: 曾宥崴(13422)
Result: AC Submission_id: 391756
Created at: Fri Nov 10 2017 18:26:40 GMT+0800 (CST)
Problem: 905 Time: 353 Memory: 6612
*/ #include <cstdio>
#include <algorithm>
#include <iostream>
using namespace std; int f[1000001],n; int main()
{
for (int i = 1; i <= 1000000; i++) f[i] = 1000000000; f[0] = 0;
for (int i = 0; i <= 1000000; i++)
for (int k = 1; i + k * k * k <= 1000000; k++)
f[i+k*k*k] = min(f[i+k*k*k],f[i] + 1); while (scanf("%d",&n) != EOF)
if (f[n] == n) printf("Oh NO!\n");
else printf("%d\n",f[n]); return 0;
}

2016级算法第三次上机-C.AlvinZH的奇幻猜想——三次方的更多相关文章

  1. 2016级算法第四次上机-F.AlvinZH的最“长”公共子序列

    940 AlvinZH的最"长"公共子序列 思路 DP,难题. \(dp[i][j]\) :记录A的前i个字符与B的前j个字符变成相同需要的最小操作数. 初始化:dp[i][0] ...

  2. 2016级算法第六次上机-F.AlvinZH的学霸养成记VI

    1082 AlvinZH的学霸养成记VI 思路 难题,凸包. 分析问题,平面上给出两类点,问能否用一条直线将二者分离. 首先应该联想到这是一个凸包问题,分别计算两类点的凸包,如果存在符合题意的直线,那 ...

  3. 2016级算法第六次上机-D.AlvinZH的学霸养成记V

    1081 AlvinZH的学霸养成记V 思路 中等题,计算几何. 这是一个排序问题,按极角排序.可以转化为叉积的应用,对于点A和B,通过叉积可以判断角度大小,共线时再判断距离. 叉积的应用.OA × ...

  4. 2016级算法第五次上机-E.AlvinZH的学霸养成记IV

    1039 AlvinZH的学霸养成记IV 思路 难题,最大二分图匹配. 难点在于如何转化问题,n对n,一个只能攻击一个,判断是否存在一种攻击方案我方不死团灭对方.可以想到把所有随从看作点,对于可攻击的 ...

  5. 2016级算法第四次上机-D.AlvinZH的1021实验plus

    978 AlvinZH的1021实验plus 思路 贪心,中等题. 使用miss变量表示未覆盖的最小数字,初始值为1. 初始覆盖区间为[1,miss),目标是覆盖[1,m],即miss需要大于m. 需 ...

  6. 2016级算法第六次上机-C.AlvinZH的学霸养成记II

    1032 AlvinZH的学霸养成记II 思路 中等题,贪心. 所有课程按照DDL的大小来排序. 维护一个当前时间curTime,初始为0. 遍历课程,curTime加上此课程持续时间d,如果这时cu ...

  7. 2016级算法第五次上机-D.AlvinZH的学霸养成记III

    850 AlvinZH的学霸养成记III 思路 难题.概率DP. 第一种思考方式:直接DP dp[i]:从已经有i个学霸到所有人变成学霸的期望. 那么答案为dp[1],需要从后往前逆推.对于某一天,有 ...

  8. 2016级算法第四次上机-C.AlvinZH的1021实验

    975 AlvinZH的1021实验 思路 贪心,简单题. 题目已经说明有且只有一种方法表示所求数,简单列举几项可以发现只由前i个砝码会可以表示[1,∑Wi]的所有数的.先找到最大需要的砝码Wi,问题 ...

  9. 2016级算法第六次上机-E.Bamboo之吃我一拳

    Bamboo之吃我一拳 分析 当两个点的距离<=d时,才可以出拳,想要使得满足出拳条件的点对最少但不为0 寻找最近点对距离,得到的最近距离能够使得可以出拳的组数最少,因为除了最近点对外其他组合均 ...

随机推荐

  1. Mask_rcnn openpose realsense

    cd /home/luo/Desktop/MyFile/Mask_RCNN_Openpose_Realsense python realsense_mask_openpose_2019032601.p ...

  2. 670. Maximum Swap 允许交换一个数 求最大值

    [抄题]: Given a non-negative integer, you could swap two digits at most once to get the maximum valued ...

  3. etherboot无盘启动

    2001.10.30 吴峰光 本站提供对无盘启动的支持.本文就此作一简单介绍. 一.概述 无盘启动,更确切的说是网络启动,可算是最为轻松和简便的启动方式了. 目前还很少有人了解它,因为目前的软硬件条件 ...

  4. redis 面试题2

    使用过Redis分布式锁么,它是什么回事? 先拿setnx来争抢锁,抢到之后,再用expire给锁加一个过期时间防止锁忘记了释放. 这时候对方会告诉你说你回答得不错,然后接着问如果在setnx之后执行 ...

  5. [C++] c pointer

    the nature of pointer const keyword const int*  p int const *p int*  const p int const a const int a ...

  6. Linux下软件常见安装方式

    pasting  分类: Linux2007-12-08 16:31 1909人阅读 评论(0) 收藏 举报 linuxredhat脚本文档managerfile        Linux下软件安装主 ...

  7. mongo学习-稀疏索引

    因为,如果要创建唯一索引,那么如果这个值有好几个为Null的,所以也会导致我们创建索引失败,那么我们可以引进系数索引这个概念,它可以做到,支持如果值存在的情况,它必须是唯一的,我们可以 将 uniqu ...

  8. REDIS与MEMCACHED的区别(转)

    出处:http://www.blogjava.net/paulwong/archive/2013/09/06/403746.html 如果简单地比较Redis与Memcached的区别,大多数都会得到 ...

  9. java Random类和Math.Rondom

      Java中存在着两种Random函数: 一.java.lang.Math.Random; 调用这个Math.Random()函数能够返回带正号的double值,该值大于等于0.0且小于1.0,即取 ...

  10. Python3 MySQL 数据库连接 -PyMySQL

    Python 3  操作mysql http://www.runoob.com/python3/python3-mysql.html Python3 MySQL 数据库连接 本文我们为大家介绍 Pyt ...