TA的每日心情 | 开心 2021-3-12 23:18 |
---|
签到天数: 2 天 [LV.1]初来乍到
|
贪婪法,又称贪心法是一种不追求最优解,只希望得到较为满意解的方法。贪婪法一般可以快速得到满意的解,因为它省去了为找最优解要穷尽所有可能而必须耗费的大量时间。
贪婪法常以当前情况为基础作最优选择,而不考虑各种可能的整体情况。
例如平时购物找钱时,为使找回的零钱的硬币数最少,不考虑找零钱的所有各种方案,而是从最大面值的币种开始,按递减的顺序考虑各币种,先尽量用大面值的币种,当不足大面值币种的金额时才去考虑下一种较小面值的币种。这就是在使用贪婪法。这种方法在这里总是最优,是因为银行对其发行的硬币种类和硬币面值的巧妙安排。
如只有面值分别为1、5和11单位的硬币,而希望找回总额为15单位的硬币。按贪婪算法,应找1个11单位面值的硬币和4个1单位面值的硬币,共找回5个硬币。但最优的解应是3个5单位面值的硬币。
【问题】 装箱问题
问题描述:装箱问题可简述如下:设有编号为0、1、…、n-1的n种物品,体积分别为v0、v1、…、vn-1。将这n种物品装到容量都为V的若干箱子里。约定这n种物品的体积均不超过V,即对于0≤i<n,有0<vi≤V。不同的装箱方案所需要的箱子数目可能不同。装箱问题要求使装尽这n种物品的箱子数要少。
对适当大的n,找出所有可能的划分要花费的时间是无法承受的。为此,对装箱问题采用非常简单的近似算法,即贪婪法。该算法依次将物品放到它第一个能放进去的箱子中,该算法虽不能保证找到最优解,但还是能找到非常好的解。不失一般性,设n件物品的体积是按从大到小排好序的,即有v0≥v1≥…≥vn-1。如不满足上述要求,只要先对这n件物品按它们的体积从大到小排序,然后按排序结果对物品重新编号即可。装箱算法简单描述如下:
输入箱子的容积;
输入物品种数n;
按体积从大到小顺序,输入各物品的体积;
预置已用箱子链为空;
预置已用箱子计数器box_count为0;
for (i=0;i<n;i++) {
从已用的第一只箱子开始顺序寻找能放入物品i 的箱子j;
if (已用箱子都不能再放物品i) {
另用一个箱子,并将物品i放入该箱子;
box_count++;
} else
将物品i放入箱子j;
}
}
上述算法能求出需要的箱子数box_count,并能求出各箱子所装物品。但不一定能找到最优解,
例:(北大百练题)
一个工厂制造的产品形状都是长方体,它们的高度都是h,长和宽都相等,一共有六个型号,他们的长宽分别为1*1, 2*2, 3*3, 4*4, 5*5, 6*6。这些产品通常使用一个 6*6*h 的长方体包裹包装然后邮寄给客户。因为邮费很贵,所以工厂要想方设法的减小每个订单运送时的包裹数量。他们很需要有一个好的程序帮他们解决这个问题从而节省费用。现在这个程序由你来设计。 输入
输入文件包括几行,每一行代表一个订单。每个订单里的一行包括六个整数,中间用空格隔开,分别为1*1至6*6这六种产品的数量。输入文件将以6个0组成的一行结尾。 输出
除了输入的最后一行6个0以外,输入文件里每一行对应着输出文件的一行,每一行输出一个整数代表对应的订单所需的最小包裹数。
样例输入
0 0 4 0 0 1
7 5 1 0 0 0
0 0 0 0 0 0 样例输出
2
1 程序:- import java.io.BufferedInputStream;
- import java.util.Scanner;
-
- /**
- * 分情况考虑贪心。关键是3*3的盒子怎么放。
- * 6*6的放满整个盒子,
- * 5*5的还可以放11个1*1。
- * 4*4的还可以放5个2*2的。
- * 3*3的总个数模4后,也就是说最后一个盒子放几个3*3的。
- * 如果是1,还可以放5个2*2和7个1*1。
- * 如果是2,可以放3个2*2和6个1*1。
- * 如果是3,可以放1个2*2和5个1*1的。
- * 2*2的模9就是最后一个箱子里放2*2的个数,36-(2*2的个数%9)就是可以放1*1的个数。
- * 最后(1*1的个数+35)/36就是最后的盒子数。
- * @author NC
- */
- public class Main {
-
- public static void main(String[] args) {
- Scanner scan = new Scanner(new BufferedInputStream(System.in));
- while (scan.hasNext()) {
- int a1 = scan.nextInt();
- int a2 = scan.nextInt();
- int a3 = scan.nextInt();
- int a4 = scan.nextInt();
- int a5 = scan.nextInt();
- int a6 = scan.nextInt();
- if (a1 == 0 && a2 == 0 && a3 == 0 && a4 == 0 && a5 == 0 && a6 == 0) {
- break;
- }
- int count = 0;
- if (a6 > 0) {
- count += a6;
- }
- if (a5 > 0) {
- count += a5;
- a1 = a1 - a5 * 11;
- }
- while (a4 > 0) {
- count++;
- if (a2 >= 5) {
- a2 -= 5;
- } else {
- a1 = a1 - (5 - a2) * 4;
- a2 = 0;
- }
- a4--;
- }
- count += a3 / 4;
- a3 = a3 % 4;
- if (a3 > 0) {
- count++;
- if (a3 == 1) {
- if (a2 >= 5) {
- a2 -= 5;
- a1 -= 7;
- } else {
- a1 = a1 - (5 - a2) * 4 - 7;
- a2 = 0;
- }
- } else if (a3 == 2) {
- if (a2 >= 3) {
- a2 -= 3;
- a1 -= 6;
- } else {
- a1 = a1 - (3 - a2) * 4 - 6;
- a2 = 0;
- }
- } else if (a3 == 3) {
- if (a2 >= 1) {
- a2 -= 1;
- a1 -= 5;
- } else {
- a1 = a1 - 4 - 5;
- a2 = 0;
- }
- }
- }
- if (a2 > 0) {
- count += a2 / 9;//最初时,犯了个超低级错误。。。。36(2*2)=18
- a2 = a2 % 9;
- if (a2 > 0) {
- count++;
- a1 = a1 - 4 * (9 - a2);
- }
- }
-
- if (a1 > 0) {
- count += a1 / 36;
- a1 = a1 % 36;
- if (a1 > 0) {
- count++;
- }
- }
- System.out.println(count);
- }
- }
- }
复制代码
源码下载:http://file.javaxxz.com/2014/11/27/000521296.zip |
|