【题解】打包装箱

1.题目

原题链接(CQBZOJ)

题目描述

学校组织了爱心捐书活动,同学们纷纷踊跃把自己看过的旧书拿出来捐给贫困山区的孩子们。图书室的马老师把同学们捐献的书打包在了6种纸箱子里(打包好的各类纸箱子有若干个),纸箱子的高相同,但底面积分为1×1,2×2,3×3,4×4,5×5,6×6。现为了装车方便,需要把这些纸箱子装在若干个6×6的木箱子,木箱子的高和打包纸箱子相同,请你帮助马老师,用最少的木箱子打包完所有的纸箱子。

输入

一行(六个数)用空格隔开,分别表示1×1,2×2,3×3,4×4,5×5,6×6六类纸箱子的个数(每类箱子的个数小于等于100)

输出

一行,最少的木箱子个数

样例输入

6 5 4 3 2 1

样例输出

7

是的,为了我们“亲爱”的mjl,我把题目改了((


2.算法分析

用最少的木箱子装完,也就是说让剩余的空间最小,最好的情况就是除了最后一个箱子,其他箱子都装满,所以只需要考虑箱子内部的情况。故这道题可以用贪心算法解决。


3.思路

要解决箱子内部如何装满的问题,我们首先需要根据题目条件建立模型。题目告诉我们有六种不同的纸箱子和木箱子的大小,根据这些条件我们可以列出箱子内部装满时的模型如下(PS:最上面的那个数字指的是最大的那个纸箱子):

自己画的图,不要管我的猛男色彩搭配【笑哭】

可以看出,在纸箱子的大小为3×3时,情况比较多比较复杂,所以需要着重考虑。

需要注意的是,在装箱的时候我们会优先把所有3×3的纸箱子装到一个木箱子里(即4个3×3的箱子装在一个木箱子里),所以剩下的那三种情况只需要判断一次。(我就是在这个地方栽的)

这里再补充两个编程的技巧(不想看请跳过):


(1)向上取整

如果一个人问大家怎么向上取整的话,估计大多数人的回答应该都是用头文件里的 \(ceil\) 函数。但是这多少有点麻烦,如果你懒得写为了方便,其实根本不需要什么函数,用整数除法就可以实现。
在c++中,整数的除法是默认为向下取整。我们假设 \(n\) 可以被 \(k\) 整除且 \(n/k=q\),那么:

\((n+1)/k==q\)

\((n+2)/k==q\)

\(......\)

\((n+k-1)/k==q\)

\((n+k)/k==q+1\)

由此可以看出,如果我们要向上取整一个除法 \(n/k\) (余数为 \(r\) ),就需要把 \(n\) 的范围提到 \(n+(k-r)\)\(n+(k-r)+(k-1)\) 这个范围之内,而当这个被除数的加数取到 \(k-1\) 的时候,不管余数怎么变,被除数永远都在这个范围。综上所述,向上取整的公式为:

\(\lceil n/k \rceil=(n+k-1)/k\)


(2)辅助数组——为“偷懒”而生

在数的计算中,我们通常要根据结果的不同而使用不同的值。这个问题可以用条件选择语句解决,但是当情况太多的时候就会造成程序的内容繁杂。(而且写着也麻烦!)当一个计算结果与一个值可以一一对应的时候,我们就可以用辅助数组简化程序。

(注:如果数与值不是一一对应的,也可以使用辅助数组,但是一定是一个值对应一个结果(也就是说不同的结果可以对应同一个值),但是在本人的学习范围之内辅助数组不能同一个结果对应多个值。)

拿这道题举例,由于3×3纸箱子的个数不一定能被4整除,这也就意味着当个数除以4的时候余数可能是0,1,2,3,不同的值对应边长为2 * 2的纸箱子在放有这些剩余的3×3的箱子的木箱子中能放得下的不同个数,计算的结果与值一一对应。所以我们可以设置一个辅助数组cnt,从0到3号位分别存储余数为0,1,2,3的不同情况所对应的值,这样我们在使用这个值的时候就可以直接调用数组,不用写条件语句。


4.编写代码

终于到了激动人心的时刻了!

AC代码(不要复制,但你要复制我也没办法):

#include<cstdio>
int cnt[4]={0,5,3,1};//辅助数组
int main(){
	int a1,a2,a3,a4,a5,a6,sum=0,x,y;
	scanf("%d %d %d %d %d %d",&a1,&a2,&a3,&a4,&a5,&a6);
  	//边长为6,5,4,3的盒子需要的箱子数  
	sum=a6+a5+a4+(a3+3)/4;
  	//边长为2的盒子在已经装了的箱子中可以装的数量     
	x=a4*5+a3*cnt[a3%4];              
	if(x<a2)sum+=(a2-x+8)/9;
        //边长为1的盒子在已经装了的箱子中可以装的数量 
	y=sum*36-a6*36-a5*25-a4*16-a3*9-a2*4;  
	if(y<a1)sum+=(a1-y+35)/36;
	printf("%d",sum);
	return 0;
} 

5.总结

这应该算是一道对于本人来说比较难的贪心,但是主要难在思路,代码不难,思路想出来题目就没多大问题了。

但是之前在做的时候一直是91分,调了很久的代码才发现x在计算的时候cnt[a3%4]不需要乘a[3],还是思路没有彻底理清楚,,ԾㅂԾ,,

posted @ 2021-04-03 19:40  Saiodgm  阅读(108)  评论(0编辑  收藏  举报