信息学奥赛一本通 1226:装箱问题 | OpenJudge NOI 4.6 19:装箱问题
【题目链接】
ybt 1226:装箱问题
OpenJudge NOI 4.6 19:装箱问题
【题目考点】
1. 贪心
【解题思路】
该题说是三维立方体,实际上无论是包裹还是产品,高度都是h,因而不用考虑高度,这实际上是二维平面上的问题。
1. 贪心选择性质的证明
贪心选择:选择最大的可以装入该包裹的产品装入该包裹
- 证明:存在最优解包含第一次的贪心选择。即存在最优解,第一个包裹中包含最大产品。
假设所有最优解都不包含第一次的贪心选择,即第一个包裹C中不包含最大的产品x。
最大的产品x一定存在于某个包裹内,记那个包裹为N。我们可以将N中的所有产品和C中的所有产品完全交换。总包裹数量不变,第一个包裹C中存在产品x,这与假设相悖,假设不成立,原命题得证。
- 证明:前k步都做贪心选择,存在最优解包含第k+1步的贪心选择。
是否做贪心选择区别在于:当前拿到一个最大的可以装入当前包裹C的产品x,是将这个产品放在当前包裹C中,还是将其放在一个新包裹N中。贪心选择是将其放在当前包裹C中。
使用反证法:假设对所有最优解,在装第k+1个产品时,当前关注的包裹C可以装入的最大产品为x,此时不进行贪心选择,不选择x,接下来只会装入大小小于x的产品。也可以说,当前包裹C中,产品x的数量不会更多。
下面考虑在N中包括x的部分产品能否和C中的一些产品或空位交换,且两包裹仍能装得下。如果可以,那么说明第k+1步进行了贪心选择,选择了产品x,总包裹数量不变,也是最优解。假设不成立,原命题得证。
- 如果N中x的数量大于C中x的数量,且x在C中与N中都是最大的产品,那么可以将N与C中的所有产品整体交换。
x为4*4、5*5、6*6都满足这一情况。或C中3*3的个数比N中3*3的个数更少。
例:x为5*5,在第k+1步往C中装产品时,没有按照贪心选择将5*5的产品装入C。后来5*5的产品装入了N,C中又装了一些产品。将C与N的所有产品交换后,C中存在贪心选择,总包裹数仍然最少,说明存在最优解在第k+1步进行了贪心选择,假设不成立,原命题得证。
以下为N中x的数量小于等于C中x的数量的情况:- 如果x是1*1的产品,那么C当时可以放1*1的产品但不放,存在一些位置空着,C中一定有可以放下1*1的空位。可以完成交换。
- 如果x是2*2的产品,那么C当时可以放2*2的产品但不放,去放1*1的产品或空着。那么在C中一定可以选择出2*2的区域,其中可以是1*1的产品也可以是空位,与x进行交换。
- 如果x是3*3的产品,说明先前加入C的是若干个3*3的产品。
- 如果C中已经有3个3*3的产品,剩下3*3的位置,这部分位置的产品或空位都可以与x进行交换。
- 如果C中已经有2个3*3的产品,且剩余的空间中摆了至多3个2*2的产品。
N中有2个3*3产品与至多3个2*2产品,此时,把N中的1个3*3与C中的2个2*2与1个1*1交换,结果为C中有3个3*3与1个2*2,N中有1个3*3与5个2*2,这种交换是可行的。
同理,如果N中有1个3*3与至多5个2*2,用N中的1个3*3交换C中的2个2*2与1个1*1是可行的。
例:将N中的红色3*3产品x与C中的蓝色两个2*2产品与1个1*1产品进行交换。交换 后一些1*1产品位置发生变化。
- 如果C中已经有1个3*3产品,剩余空间摆了至多5个2*2的产品。N中有1个3*3产品与至多5个2*2的产品,用N中的1个3*3交换C中的2个2*2与1个1*1是可行的。
如果待交换的产品没有那么多,可以用空位代替。
例:将N中的红色3*3产品x与C中的蓝色两个2*2产品与1个1*1产品进行交换。交换 后一些1*1产品位置发生变化。
- x不可能是4*4或更大的产品,如果是,C中可以放x但不放,C中的x只能是0个,而N中的x有1个,这是前面已经讨论过的“如果N中x的数量大于C中x的数量”的情况。
因此N中包括x的部分产品总能和C中的一些产品或空位交换位置。说明第k+1步进行了贪心选择,选择了产品x,总包裹数量不变,也是最优解。因而假设不成立,原命题得证。
2. 具体做法
考虑各种情况下,剩下的空间最多可以放下几个各种产品,总结成表格
已有 | 最多放几个3*3 | 最多放几个2*2 | 最多放几个1*1 |
---|---|---|---|
1个6*6 | 0 | 0 | 0 |
1个5*5 | 0 | 0 | 11 |
1个4*4 | 0 | 5 | 20 |
1个3*3 | 3 | 5 | 27 |
2个3*3 | 2 | 3 | 18 |
3个3*3 | 1 | 1 | 9 |
无 | 4 | 9 | 36 |
此这基础上,每多放一个2*2,1*1可放个数减4。
观察规律,1*1可以放的个数就是总面积6*6减去所有放入其中的产品的总面积。
在已有3*3的情况下,每多放入一个3*3,2*2可以放入的个数减2。
这里只需要设数组记录放入1个某大小产品后,其他大小产品可以放入的数量。
从大到小遍历各个产品,找到一个产品,开一个新包裹将其放入。如果剩余位置还可以放产品,那么放入对应产品,改变剩余位置可放产品的数量。直到没有位置可放或没有足够的产品可放为止。再从大到小找下一个产品,开一个新包裹将其放入。重复上述过程,直到看完所有产品为止。
【题解代码】
解法1:贪心(本人原创)
#include <bits/stdc++.h>
using namespace std;
int status[8][4];//status[i][j]:包裹中已有1个大小为i*i的产品,此时可以最多放入多少个j*j的产品
void initStatus()
{//status[0]:包裹中没有产品时,各种产品最多可以放多少个 status[2][2] = 8;status[3][2] = 5, status[3][3] = 3;status[4][2] = 5;for(int i = 1; i <= 6; ++i)status[i][1] = 36 - i*i;
}
int pro[8];//pro[i]:i*i产品的数量
int main()
{initStatus(); while(true){int sum = 0, bag = 0, rem[8];//sum:总产品数量 bag:包裹数 rem[i]:当前剩余空间能放几个i*i for(int i = 1; i <= 6; ++i){cin >> pro[i];sum += pro[i];}if(sum == 0)//如果6个数都是0,那么加和为0,要跳出循环 break;for(int i = 6; i >= 1; --i){while(pro[i] > 0){bag++;//用一个新包裹放i*ipro[i]--;for(int j = 1; j <= 3; ++j)//获取当前剩余空间情况 rem[j] = status[i][j];int j = 3;while(j >= 1){if(rem[j] > 0 && pro[j] > 0)//如果可以放j*j的产品 {pro[j]--;//放一个产品 if(j == 3){rem[3]--;rem[2] -= 2;rem[1] -= 9;}else if(j == 2){rem[2]--;rem[1] -= 4;}else//j == 1rem[1]--;}else--j;}} }cout << bag << endl;} return 0;
}
解法2:手动完成贪心过程
思路来自zqhf123博客:zqhf123 1226:装箱问题
由于箱子种类不多,我们可以手动完成每一步的贪心行为。先装大产品,看占了多少空间,剩下多少空间。再看小产品。逐次算出当前可以给下一个产品留出的空位。
#include<bits/stdc++.h>
using namespace std;
int bag;//总包裹数
int k[4] = {0, 5, 3, 1};//k[i]表示3*3的产品有i个时(k[0]表示有4个时)剩余空间可以放2*2产品的个数
int pro[8], p2, p1;//p2:2*2空位数 p1:1*1空位数
int main()
{ while(true){for(int i = 1; i <= 6; ++i)cin >> pro[i];if(pro[1] == 0 && pro[2] == 0 && pro[3] == 0 && pro[4] == 0 && pro[5] == 0 && pro[6] == 0) break;bag = pro[6] + pro[5] + pro[4] + ceil(pro[3]/4.0);//6*6和5*5和4*4一定是一个占一个箱子,而3*3 4个占一个箱子p2 = 5*pro[4]+k[pro[3]%4];//k[pro[3]%4]:有pro[3]%4个3*3在一个包裹中时,剩下的位置可以放2*2的数目 if(pro[2] > p2)//2*2的个数比我们留出来为2*2的空间个数多,就需要为2*2另开箱子bag += ceil((pro[2]-p2)/9.0);//多出来的2*2箱子应该占用的新箱子数 p1 = 36*bag-36*pro[6]-25*pro[5]-16*pro[4]-9*pro[3]-4*pro[2];//求出当前包裹中所有剩下的可以放1*1的位置数 if(pro[1] > p1)//如果1*1的个数,比我们留出的空间多就需要另开空间 bag += ceil((pro[1]-p1)/36.0);//将多出来的另开箱子 cout << bag << endl;}return 0;
}
信息学奥赛一本通 1226:装箱问题 | OpenJudge NOI 4.6 19:装箱问题相关推荐
- 信息学奥赛一本通(2049:【例5.19】字符串判等)
2049:[例5.19]字符串判等 时间限制: 1000 ms 内存限制: 65536 KB 提交数: 842 通过数: 254 [题目描述] 判断两个由大小写字母和空格组成的 ...
- 信息学奥赛一本通(2033:【例4.19】阶乘之和)
2033:[例4.19]阶乘之和 时间限制: 1000 ms 内存限制: 65536 KB 提交数: 1896 通过数: 313 [题目描述] 输入nn,计算S=1!+2!+3 ...
- 信息学奥赛一本通 1209:分数求和 | OpenJudge NOI 1.13 12:分数求和
[题目链接] ybt 1209:分数求和 OpenJudge NOI 1.13 12:分数求和 [题目考点] 1. 求最大公约数 2. 求最小公倍数 [解题思路] 求最大公约数,可以用辗转相除法.具体 ...
- 信息学奥赛一本通 1294:Charm Bracelet | OpenJudge NOI 2.6 7113:Charm Bracelet | 洛谷 P2871
[题目链接] ybt 1294:Charm Bracelet OpenJudge NOI 2.6 7113:Charm Bracelet 洛谷 P2871 [USACO07DEC]Charm Brac ...
- 信息学奥赛一本通 2050:【例5.20】字串包含 | OpenJudge NOI 1.17 19:字符串移位包含问题
[题目链接] ybt 2050:[例5.20]字串包含 OpenJudge NOI 1.17 19:字符串移位包含问题 [题目考点] 1. 字符串 2. 判断一个字符串是不是另一个字符串的子串(字符串 ...
- 信息学奥赛一本通 1073:救援 | OpenJudge NOI 1.5 19:救援
[题目链接] ybt 1073:救援 OpenJudge NOI 1.5 19:救援 [题目考点] 1. 直角坐标系下某点到原点的距离 点(x,y)(x,y)(x,y)到原点的距离d=x2+y2d = ...
- 信息学奥赛一本通 1057:简单计算器 | OpenJudge NOI 1.4 19
[题目链接] ybt 1057:简单计算器 OpenJudge NOI 1.4 19:简单计算器 [题目考点] 1. switch语句 2. if-else if-else语句 [题解代码] 解法1: ...
- 信息学奥赛一本通 1036:A×B问题 | OpenJudge NOI 1.3 19
[题目链接] ybt 1036:A×B问题 OpenJudge NOI 1.3 19:A*B问题 [题目考点] 1. 不同整型数据的范围 类型 占用字节数 可表示数字范围 char 1 -127~12 ...
- 信息学奥赛一本通(基础算法与数据结构-题解汇总目录)
信息学奥赛一本通(C++版)在线评测系统 基础(二)基础算法 更新中...... 第一章高精度计算 1307[例1.3]高精度乘法 1308[例1.5]高精除 1309[例1.6]回文数(Noip ...
最新文章
- 似水流年,美丽清华园
- @Configuration
- 塔菲尔曲线斜率的大小_分段函数函数值(自变量)大小(范围)的六种题型
- 附录:MySQL忘记root密码
- Greg and Array CodeForces - 296C(差分数组+线段树)
- 谷歌开源的 GAN 库--TFGAN
- ccf json解析 java,【求助】e4a json解析 求助大佬帮忙老看下怎么取?
- Python最实用的25个小技巧
- python selenium list index out of range
- 做开源 18 年,他想把中国开源带向世界 | 人物志
- “中国互联网100强”(2013)发布
- bootstrap 获取表格修改的结果_bootstrap table getData获取表格数据的方法
- Linu下安装ffmpeg
- MAC - 必备软件安装与使用
- 黑马Python笔记3
- 照片宽高比怎么设置_【经验分享】照片处理
- IntelliJ IDEA 激活 破解补丁
- 抑郁焦虑测试软件可信度,做题自测抑郁症可靠吗
- Cross Domian iFrame Exceptions 跨域iFrame屏蔽例外
- 初学画画怎么画线稿?学画线稿的方法有哪些?
热门文章
- lucene 多索引目录搜索实现方法
- [转载]Windowsnbsp;Servernbsp;2008nbsp;R2nbsp;之二十五ADnbsp;RMS信任策略
- webservice 心得
- 进程函数一步步理解Linux进程(2)--进程编程进程函数
- ios公司开发者账号申请分享攻略
- 刚刚!阿里云宣布2021要“做厚中台”!有哪些书值得读?
- 深入线程池的问题连环炮
- 阿里高级技术专家张建飞:深度剖析领域模型vs数据模型的用法
- ElementUI + express实现头像上传及后台图片保存
- 分布式开发必须了解的Zookeeper的Leader选举机制(源码解析)