首页 > 试题广场 >

装箱

[编程题]装箱
  • 热度指数:1081 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 32M,其他语言64M
  • 算法知识视频讲解
一个工厂制造的产品形状都是长方体,它们的高度都是h,长和宽都相等,一共有六个型号,他们的长宽分别为1×1、2×2、3×3、4×4、5×5、6×6。这些产品通常使用一个 6×6×h 的长方体包裹包装然后邮寄给客户。因为邮费很贵,所以工厂要想方设法的减小每个订单运送时的包裹数量。他们很需要有一个好的程序帮他们解决这个问题从而节省费用。现在这个程序由你来设计。

输入描述:
输入包含多组数据。

每组数据一行,包含六个自然数,分别表示1×1至6×6这六种产品的数量。


输出描述:
对应每组输入,输出最小的包裹数。
示例1

输入

0 0 4 0 0 1
7 5 1 0 0 0

输出

2
1
由于高均为h,那么装的数目最多,就要求一个6*6的平面容纳最多的方块,这是得到的箱子数目最少。
6*6的必须用一个箱子。
5*5的必须用一个,
4*4需要一个,剩余位置可以放5个2*2。
3*3 分情况,如3*3箱子数目是4的整数倍,那么除/4得到需要的箱子。若是4n+1则,空余位置可以放可以放5个2*2,若是4n+2可以放3个2*2,
若是4n+3可以放1个2*2。
2*2,1*1 可以放到上述空余位置,如果没有了空余位置在考虑使用新的箱子装。

发表于 2015-10-29 15:13:23 回复(0)
更多回答
不需要很长。。十几行可以了。。
#include "iostream" //CPP
using namespace std; //CPP
int s1,s2,s3,s4,s5,s6,o2,o1,z;
int main(void){
while(cin>>s1>>s2>>s3>>s4>>s5>>s6){
z = s4 + s5 + s6; //z是一共需要的箱子数。先算4*4 5*5 6*6需要的箱子数(一箱只能装一个)
z += (s3%4>0)? (s3/4+1) : (s3/4);//z加上 3*3需要的箱子数
o2 = (s3%4>0)? (s4*5+(7-2*(s3%4))) : (s4*5);//剩下的2*2空间。注:3*3一箱装不满的有s3%4个,剩下空间2*2还可以装7-2(s3%4)个(s3%4为0则这项去掉),加上4*4的,共还剩s4*5+(7-2*(s3%4))个2*2空间
if(s2 > o2){  //剩下的装满2*2后溢出
    z += ((s2-o2)%9>0)? ((s2-o2)/9+1) : ((s2-o2)/9);//z加上 多出来的2*2需要的箱子数
    if((s2-o2)%9>0) o1 = (s3%4>0)? (s5*11 +(8-s3%4)+(36-4*((s2-o2)%9))) : (s5*11+(36-4*((s2-o2)%9)));//剩下的1*1空间。注:3*3一箱装不满的有s3%4个,剩下空间装满2*2后还可以塞(8-s3%4)个1*1(s3%4为0则这项去掉)。2*2装不满的有(s2-o2)%9,还剩36-4*((s2-o2)%9)个1*1空间((s2-o2)%9为0则这项去掉)。
    if((s2-o2)%9==0) o1 = (s3%4>0)? (s5*11+(8-s3%4)) : (s5*11);//剩下的1*1空间(也是要分 多的2*2是否被整除即(s2-o2)%9为0与否 的情况讨论,和条件运算符一个意思)
    if(s1 > o1) z += ((s1-o1)%36>0)? ((s1-o1)/36+1) : ((s1-o1)/36);//z加上 多出来的1*1需要的箱子数   
} 
else{//剩下的刚好装2*2甚至有富余
    o1 = (s3%4>0)? (s5*11+(8-s3%4)+(o2-s2)*4) : (s5*11+(o2-s2)*4);//剩下的1*1空间。2*2若刚好装满还有s5*11+(8-s3%4)个1*1空间(s3%4为0则去掉(8-s3%4)),若少几个2*2则多几个4倍的1*1空间
    if(s1 > o1) z += ((s1-o1)%36>0)? ((s1-o1)/36+1) : ((s1-o1)/36);//z加上 多出来的1*1需要的箱子数       
}
cout<<z<<endl;
}
return 0;
}
通过
发表于 2015-09-21 01:04:44 回复(0)
贪心法处理
#include<iostream>
#include<vector>
#include<string>
#include<algorithm>
#include<functional>
#include <map>
#include <set>
#include <unordered_set>
#include <unordered_map>
#include <exception>
#include <iomanip>
#include <memory>
#include <sstream>

#define INF 1000000
using namespace std;

int main(int argc, char** argv)
{
	//freopen("in.txt", "r", stdin);
	int w1, w2, w3, w4, w5, w6;
	while (cin >> w1 >> w2 >> w3 >> w4 >> w5 >> w6)
	{
		int leftRegion = 0;
		int res = w6;
		res += w5;
		leftRegion = w5 * 11;
		w1 = max(0,w1 - w5 * 11);
		res += w4;
		leftRegion = 20 * w4;
		if (leftRegion <= w2 * 4){ w2 -= leftRegion / 4; leftRegion = 0; }
		else {leftRegion -= w2 * 4; w2 = 0; }
		if (leftRegion > 0) w1 = max(0, w1 - leftRegion);
		res += w3 / 4;
		w3 %= 4;
		if (w3 > 0)
		{
			++res;
			leftRegion = (4 - w3) * 9;
			if (leftRegion <= w2 * 4){ w2 -= leftRegion / 4; leftRegion = 0; }
			else { leftRegion -= w2 * 4; w2 = 0; }
			if (leftRegion > 0) w1 = max(0, w1 - leftRegion);
		}
		res += w2 / 9;
		w2 %= 9;
		if (w2 > 0)
		{
			++res;
			leftRegion = (9 - w2) * 4;
			w1 = max(0, w1 - leftRegion);
		}
		res += w1 / 36;
		if (w1 % 36 > 0) ++res;
		cout << res << endl;
	}

	return 0;
}

发表于 2017-07-13 19:26:26 回复(0)
用比较笨的数学方法去凑,原则就是贪心,先装大的再把小的往里面塞。
i*i的产品有arr[i]个,进行数学分析:
(1) 由于6*6,5*5,4*4的产品要占一个包裹,一个包裹最多能装4个3*3的产品。因此包裹数可以先初始化为:arr[6] + arr[5] + arr[4] + ceil(arr[3] / 4)
然后我们将2*2和1*1的产品先填入到这些包裹的空隙中
(2) 5*5产品所占的包裹只能再填1*1的产品。如果空间能够装下所有的1*1产品,就暂时无需增加包裹,否则填满这些空间后还会余下1*1的产品,再考虑往4*4产品所在包裹放。
(3) 4*4产品所占的包裹可以再填2*2的产品也可以再填1*1的产品。先将2*2的产品往里放,最多可以放5个,如果所有4*4产品所占包裹的剩余空间能够装下所有2*2的产品,就暂时无需再增加包裹,然后往剩余的空间放1*1的产品(也可能已经没有了)。如果放不下,就继续考虑将余下的2*2和1*1产品往3*3产品所在的包裹放。
(4) 3*3产品所占的包裹可以再填2*2的产品也可以再填1*1的产品(如果一个包裹中只有一个3*3产品,可以放5个2*2产品+7个1*1产品;有连两个3*3产品,可以放3个2*2产品+6个1*1产品;有三个3*3产品,可以放1个2*2产品+5个1*1产品)。先将2*2的产品往里放,无法再放2*2的产品了就再往剩余空间放1*1的产品。
(5) 经历了(1)-(4)如果还剩下1*1和2*2的产品,就需要增加新的包裹,还需要ceil((arr[1]+4*arr[2])/36)个。
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String line;
        while((line = br.readLine()) != null){
            if(line.equals("0 0 0 0 0 0")) break;
            String[] params = line.split(" ");
            int[] size = new int[7];
            for(int i = 0; i < 6; i++) size[i + 1] = Integer.parseInt(params[i]);
            // 尺寸为6*6,5*5和4*4的产品必须要占一个包裹,一个包裹最多能装4个尺寸为3*3的产品
            int count = size[6] + size[5] + size[4] + (size[3] + 3)/4;
            size[3] %= 4;     // 剩下3*3尺寸的产品数
            // 5*5产品占的包裹中只能再塞1*1的产品
            int remain1 = Math.max(0, size[1] - size[5]*11);    // 装完5*5产品所在的包裹后,剩下的1*1产品
            // 4*4产品占的包裹中能再塞1*1和2*2的产品
            int remain2 = 0;        // 装完4*4产品所占包裹后,剩下的2*2产品
            int remainSpace = 0;    // 剩余空间
            if(size[2] > size[4]*5){
                remain2 = size[2] - size[4]*5;     // 放了一个4*4产品之后还能放5个2*2产品
            }else{
                // 装完2*2产品看看4*4产品占的包裹还剩下多少空间
                remainSpace = size[4]*20 - size[2]*4;
                // 有多余的空间就用来放1*1的产品
                remain1 = Math.max(0, remain1 - remainSpace);
            }
            // 3*3产品占的包裹中能再塞1*1和2*2的产品,分为三种情况
            if(size[3] == 1){
                if(remain2 > 5){
                    remain2 -= 5;     // 3*3产品所占包裹最多还能装5个2*2产品
                    remain1 = Math.max(0, remain1 - 7);    // 余下的空间还可以继续装1*1产品
                }else{
                    // 装完2*2产品看看3*3产品占的包裹还剩下多少空间
                    remainSpace += 27 - remain2*4;
                    // 有多余的空间就用来放1*1的产品
                    remain1 = Math.max(0, remain1 - remainSpace);
                    remain2 = 0;
                }
            }
            if(size[3] == 2){
                if(remain2 > 3){
                    remain2 -= 3;
                    remain1 = Math.max(0, remain1 - 6);
                }else{
                    remainSpace += 18 - remain2*4;
                    remain1 = Math.max(0, remain1 - remainSpace);
                    remain2 = 0;
                }
            }
            if(size[3] == 3){
                if(remain2 >= 1){
                    remain2 -= 1;
                    remain1 = Math.max(0, remain1 - 5);
                }else{
                    remainSpace += 9;
                    remain1 = Math.max(0, remain1 - remainSpace);
                    remain2 = 0;
                }
            }
            // 最后如果还剩下1*1和2*2的产品,就开新的包裹
            count += (remain1 + 4*remain2 + 35)/36;
            System.out.println(count);
        }
    }
}

编辑于 2021-07-17 22:47:46 回复(0)
# 假设1x1到6x6的产品各自有a,b,c,d,e,f个

# 对于6x6的产品,一个箱子最多只能装入1个,无剩余空间
# 因此,所有6x6的产品总共需要的箱子数=1x1的产品数f

# 对于5x5的产品,一个箱子最多只能装入1个,剩余空间可以装入11个1x1的产品
# 因此,所有5x5的产品总共需要的箱子数=5x5的产品数e

# 对于4x4的产品,一个箱子最多只能装入1个,剩余空间可以装入5个2x2的产品
# 因此,所有4x4的产品总共需要的箱子数=4x4的产品数d

# 对于3x3的产品,一个箱子可以装1个、2个、3个或者4个
# (1)如果装入1个3x3的产品,那么剩余空间可以装入5个2x2的产品+7个1x1的产品
# (2)如果装入2个3x3的产品,那么剩余空间可以装入3个2x2的产品+6个1x1的产品
# (3)如果装入3个3x3的产品,那么剩余空间可以装入1个2x2的产品+5个1x1的产品
# (4)如果装入4个3x3的产品,无剩余空间
# 因此,所有3x3的产品总共需要的箱子数=(3x3的产品数c+3)//4

# 对于2x2的产品,一个箱子可以装9个,无剩余空间
# 同时注意到:
# 装有4x4产品的箱子还可以装入5个2x2的产品,
# 装有3x3产品的箱子,也还可以装入若干个2x2的产品,对应关系如下:
#       装入1个3x3的产品,剩余空间还可以装入5个2x2的产品
#       装入2个3x3的产品,剩余空间还可以装入3个2x2的产品
#       装入3个3x3的产品,剩余空间还可以装入1个2x2的产品
# 本着使用最少箱子数的原则,有2x2产品的空余位置则优先填补到空余位置
# 因此,如果所有2x2产品总共需要的箱子数小于当前空余位置数,则无需为2x2的产品开辟新的箱子,否则,计算没装完的2x2的产品数,开辟新的箱子

# 至此,对于3x3,4x4、5x5和6x6的产品,总共需要的箱子数=`(c+3)//4+d+e+f`
# 对于2x2的产品,一个4x4的产品占用一个箱子,剩余位置可以装入5个2x2的产品
#               剩余3x3产品的个数与剩余3x3产品所在箱子剩余位置可以装入的2x2产品的数量对应关系为:{4:0, 1:5, 2:3, 3:1},
#               用数组表示为arr=[0,5,3,1],数组下表是剩余3x3产品数,数组元素是对应空余位置能装入的2x2的产品数
# 因此,对于2x2的产品,如果2x2产品数小于剩余空闲位置能够容纳的2x2产品数=`d*5+arr[c%4]`,那么无需额外开辟新的箱子
#                    反之,计算多出来无法装入的2x2产品数,这些多出来的2x2产品(假设有num个)总共需要的箱子数=(num+8)//9

# 最后,对于1x1的产品,将全部空间减去2x2到6x6产品所占用的空间need1num=box_num*36-(f*36+e*25+d*16+c*9+b*4),看看剩余空间能不能装入全部的1x1产品
# 如果能,那么无需开辟新的箱子,否则,多出来num=a-need1num个箱子,那么总共需要新开辟的箱子数=(num+35)//36
# 注意,在计算2x2产品需要的箱子数时,已经包含了将2x2产品装入到4x4和3x3产品所在箱子剩余空闲位置这一事实

def box(a,b,c,d,e,f):
    # 3x3到6x6的产品需要的箱子数
    box=(c+3)//4+d+e+f
    
    arr=[0,5,3,1]#4,1,2,3个3x3产品对应剩余位置能够装入的2x2产品数
    # 3x3到6x6的产品(其实就是4x4和3x3的)需要的箱子剩余未知能够容纳的2x2产品数
    need2num=d*5+arr[c%4]
    # 2x2产品需要的箱子数
    if need2num<b:
        box+=((b-need2num)+8)//9

    # 1x2到6x6的产品(其实就是5x5,4x4,3x3和2x2的)需要的箱子剩余未知能够容纳的1x1产品数
    need1num=box*36-(f*36+e*25+d*16+c*9+b*4)
    # 1x1产品需要的箱子数
    if need1num<a:
        box+=((a-need1num)+35)//36
    
    return box

while True:
    try:
        a,b,c,d,e,f=list(map(int,input().split(' ')))
        res=box(a,b,c,d,e,f)
        print(res)
    except:
        break

发表于 2022-06-30 12:58:17 回复(0)
笨办法,从装5X5的箱子开始计算分别能装入多少1X1、2X2的,等1X1和2X2的都装满了就终止,如果2X2的被多存放了(就是实际没有那么多2X2),再用1X1的去占这些2X2的份额
is_empty = [0] * 6
while True:
    try:
        parcels = list(map(int, input().split()))
        if parcels == is_empty:
            print(0)
            continue
        sealed, parcels[2] = divmod(parcels[2], 4)
        sealed += sum(parcels[3:])
        
        parcels[0] -= parcels[4] * 11
        can_pack = [0, parcels[3] * 5]
        if parcels[2] > 0:
            sealed += 1
            tmp = 9 - 2*(parcels[2] + 1)
            can_pack[1] += tmp
            can_pack[0] = 36 - parcels[2]*9 - tmp*4
        parcels[1] -= can_pack[1]
        parcels[0] -= can_pack[0]
        if parcels[1] <= 0:
            parcels[0] += parcels[1] * 4
            if parcels[0] <= 0:
                print(sealed)
                continue
        tmp = int(parcels[1]//9)
        parcels[1] = parcels[1] - tmp*9
        sealed += tmp
        if parcels[1] > 0:
            sealed += 1
            parcels[0] -= 36 - parcels[1]*4
        if parcels[0] > 0:
            tmp = parcels[0] % 36
            sealed += parcels[0]//36 if tmp == 0 else parcels[0]//36 + 1
        print(sealed)
    except:
        break


发表于 2021-08-02 17:04:11 回复(0)
发表于 2015-10-22 15:02:43 回复(1)
#include<iostream>
using namespace std;
int f(int a[6])
{ int s1=0,s2=0;//s1 s2分别代表剩下可以装1*1和2*2的最大值
 int num=0;//用于存放返回值
 
 // 6*6 5*5 4*4的情况
 if(a[5]>0)  //6*6
 num+=a[5];
 
 if(a[4]>0)  //5*5
 {num+=a[4];
  s1+=a[4]*11;
 }
 if(a[3]>0)   //4*4
 {num+=a[3];
  s1+=a[3]*20;
  s2+=a[3]*5;
 }
// 3*3
 if(a[2]>0)
 { num+=(a[2]-1)/4+1;
    int j=a[2]%4;
 
    if(j>0)
     {s1+=36-j*9;
      s2+=7-2*j;}
 }
 
 //2*2
 if(a[1]>0)
 {if(a[1]<=s2)
 s1=s1-4*a[1] ;
 else if(a[1]>s2)
 { num+=((a[1]-s2)-1)/9+1; //用新的去放2*2
 int k=(a[1]-s2)%9;
 if(k>0)
 { s1+=36-k*4;
  }
  s1=s1-4*s2;
  
 }
 
}
//1*1
if(a[0]>0)
{if(a[0]<=s1)
return num;
else 
{num+=((a[0]-s1)-1)/36+1;
 
}
 
}
 return num;
} 
int main()
{  int a[6];//用于存放输入
   int i=0;
   while(cin>>a[i++])
   {
 
 if(i==6)
{ cout<<f(a)<<endl;//输出结果 
        i=0;}
}
 
 return 0;
 } 

发表于 2015-09-20 16:30:34 回复(0)

import java.util.Scanner;

public class Main {

public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int[] a = new int[6];
while(sc.hasNext()){
for(int i = 0; i < 6; i++)
a[i] = sc.nextInt();
System.out.println(min(a));
}
}

public static int min(int[] a){
int count = a[5] + a[4] + a[3];
//5*5  (5 + 1 * 11)
if(a[4] > 0){
//填充11个1*1
a[0] = a[0] - a[4]*11;
if(a[0] < 0) a[0] = 0;
}
//4*4
if(a[3] > 0){
//填充5个2*2
a[1] = a[1] - a[3] * 5;
//2*2不够,用4个1*1代替填充
if(a[1] < 0){
int need = -a[1] * 4;
if(need < a[0]) a[0] = a[0] - need;
else a[0] = 0;
                
                a[1] = 0;
}
}
//4个3*3 
count += a[2] / 4;
a[2] = a[2] % 4;
if(a[2] > 0){
//有剩余再加1个
count ++;
//尽量多用2*2填
int need2 = 0;//2*2个数
if(a[2] == 3){
need2 = 1;
}else if(a[2] == 2){
need2 = 3;
}else if(a[2] == 1){
need2 = 5;
}
int need = 0;//1*1个数
if(a[1] > need2){
a[1] = a[1] - need2;
need = 36 - a[2]*9 - need2*4;
}else{
a[1] = 0;
need = 36 - a[2]*9 - a[1]*4;
}
if(a[0] > need){
a[0] = a[0] - need;
}else{
a[0] = 0;
}
}
//9个2*2
count += a[1] / 9;
a[1] = a[1] % 9;
if(a[1] > 0){
count ++;
//4个1*1拼一个2*2
int need = a[1] * 4;
if(a[0] > need) a[0] = a[0] - need;
else a[0] = 0;
}
//36个1*1
count += a[0] / 36;
if(a[0] % 36 != 0) count ++;
return count;
}
}

发表于 2015-08-26 21:14:35 回复(0)