Java学习者论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

手机号码,快捷登录

恭喜Java学习者论坛(https://www.javaxxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,购买链接:点击进入购买VIP会员
JAVA高级面试进阶视频教程Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程

Go语言视频零基础入门到精通

Java架构师3期(课件+源码)

Java开发全终端实战租房项目视频教程

SpringBoot2.X入门到高级使用教程

大数据培训第六期全套视频教程

深度学习(CNN RNN GAN)算法原理

Java亿级流量电商系统视频教程

互联网架构师视频教程

年薪50万Spark2.0从入门到精通

年薪50万!人工智能学习路线教程

年薪50万!大数据从入门到精通学习路线年薪50万!机器学习入门到精通视频教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程 MySQL入门到精通教程
查看: 1077|回复: 0

学习java常用算法之(2)贪婪法

[复制链接]

该用户从未签到

发表于 2011-9-18 16:55:40 | 显示全部楼层 |阅读模式
贪婪法,又称贪心法是一种不追求最优解,只希望得到较为满意解的方法。贪婪法一般可以快速得到满意的解,因为它省去了为找最优解要穷尽所有可能而必须耗费的大量时间。

   贪婪法常以当前情况为基础作最优选择,而不考虑各种可能的整体情况。

   例如平时购物找钱时,为使找回的零钱的硬币数最少,不考虑找零钱的所有各种方案,而是从最大面值的币种开始,按递减的顺序考虑各币种,先尽量用大面值的币种,当不足大面值币种的金额时才去考虑下一种较小面值的币种。这就是在使用贪婪法。这种方法在这里总是最优,是因为银行对其发行的硬币种类和硬币面值的巧妙安排。

   如只有面值分别为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);   
        }   
    }   
}  
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|Java学习者论坛 ( 声明:本站资料整理自互联网,用于Java学习者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

GMT+8, 2025-1-10 23:17 , Processed in 0.394446 second(s), 37 queries .

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表