关于贪心算法

2023-11-08

贪心算法(Greedy algorithm),又称贪婪算法。是一种在每一步选择中都采取在当前状态下最好或最优(即最有利)的选择,从而使得问题得到全局最优解。

贪心的算法的设计就是要遵循某种规则,不断地选取当前最优解的算法设计方法。

贪心算法基本概念

贪心算法与枚举法的不同之处在于每个子问题都选择最优的情况,然后向下继续进行,且不能回溯,枚举法是将所有情况都考虑然后选出最优的情况。

贪心算法,在对问题求解时,不从整体考虑,而是采用一叶障目的选择方式,只选择某种意义上的局部最优解。并且,贪心算法是没有固定的模板可以遵循的,每个题目都有不同的贪心策略,所以算法设计的关键就是贪心策略的选择。

贪心算法有一个必须要注意的事情。贪心算法对于问题的要求是,所有的选择必须是无后效性的,即当前的选择,不能影响后续选择对于结果的影响。

贪心算法主要适用于最优化问题,如:MST(最小生成树) 问题。有时候贪心算法并不能得到最优答案,但是能得到精确答案的近似答案。有时可以辅助其他算法得到不是那么精确的结果。

适用范围

符合贪心策略:

所谓贪心选择性质是指所求问题的整体最优解可以通过一系列局部最优的选择,即贪心选择来达到。这是贪心算法可行的第一个基本要素,也是贪心算法与动态规划算法的主要区别。

所谓的贪心选择性质就是,该问题的每一步选择都在选择最优的情况下能够导致最终问题的答案也是最优。

或者说是无后效性,如果该问题的每一步选择都对后续的选择没有影响,就可以是应用贪心算法。

贪心算法的设计步骤:

  1. 证明原问题的最优解之一可以由贪心选择得到。
  2. 将最优化问题转化为这样一个问题,即先做出选择,再解决剩下的一个子问题。
  3. 对每一子问题一一求解,得到子问题的局部最优解;
  4. 把子问题的解局部最优解合成原来解问题的一个解

找零问题

假设商店老板需要找零 n 元钱。
 钱币的面额有:100 元、50 元、20 元、5 元、1 元、如何找零使得所需钱币的数量最少?
 注意:n 可能为 0,也能为几百元(别问,问就是微信提现来了)

输入说明:
 在第一行给出测试例个数 N。1<=N<=10^5
代表需要找零的钱数。

输出说明:
 有 5 行输出数据,每一行输出数据输出找零的金额与数量,详情看样例。
输入样例:
 365
输出样例: 
100:3
50:1
20:0
5:3
1:0

运行限制:

最大运行时间:1s
最大运行内存:128M

我们都知道从大的钱开始找钱。这就是一种贪心的思想,将大问题转化为一个个小的子问题,每次选择最大的钱数使得总量最小。

代码如下:

import java.util.Arrays;
import java.util.Comparator;
import java.util.Scanner;
 
import static java.lang.Integer.max;
 
public class Main {
 
 
  //面值
  static  int t[] = new int[]{100, 50, 20, 5, 1};
 
  //张数
  static int m[] = new int[5];
 
  static void change(int n) {
 
      for (int i = 0; i < 5; i++) {
          m[i] = n / t[i];
 
          n = n % t[i];
 
          //print("%d",n);
      }
 
  }
 
  public static void main(String[] args) {
 
      int N;
 
      Scanner in = new Scanner(System.in);
 
      N = in.nextInt();
 
      change(N);
 
      for (int i = 0; i < 5; i++) {
          System.out.println(String.format("%d:%d", t[i], m[i]));
      }
  }
} 

 活动选择型问题——小 B 的宿舍

小 B 的宿舍楼沿着走廊南北向的两边各有 200 个房间。
 如图所示:
[房间1][房间3][房间5][房间7][房间9 ]...[房间399]
----------------------------------------------
                   走廊
----------------------------------------------
[房间2][房间4][房间6][房间8][房间10]...[房间400]
 
最近,由于转专业和专业分流的原因,宿舍将迎来新的调整,以便组成新的班级后方便管理。
但是由于走廊狭窄,走廊里只能通过两个搬运的物品(可以同向也可以反向),因此必须指定高效的搬运计划。
老师给了每位同学下达了以下要求,让同学们提前收拾好行李,然后给每位同学 10 分钟的时间搬运。
当房间 i 搬运行李到 j 时,i 与 j 之间的走廊都会被占用,但是可以容纳两个不同同学同时搬运。所以,10 分钟之内同一段走廊最多两个人同时搬运,不重叠的走廊也可以同时搬运。
小 B 的老师是个数学老师,经过运筹学一通计算他得到了最优的搬运计划。
虽然计划不唯一,但是最优值唯一,请问这个最短时间是多少?

输入说明:
输入数据有 T 组测试例,在第一行给出测试例个数 T。 
每个测试例的第一行是一个整数 N(1≤N≤200),表示要搬运行李的人数。接下来 N 行,每行两个正整数 s 和 t,表示一个人,将行李是从房间号码 s 移到到房间号码 t。
 输出说明:
 每组输入都有一行输出数据,为一整数 T,表示完成任务所花费的最小时间。
输入样例: 
3
4
10 20
30 40
50 60
70 80
2
1 3
2 200
3
10 100
20 80
30 50
输出样例:
10
10
20

运行限制:

最大运行时间:1s
最大运行内存:128M

 该题属于贪心算法,因为它尽可能使搬运行李同时进行,以便使单独安排的搬运次数最少。这样用的时间最少,即所用最少时间为不能同时搬运行李的次数,进而转化为寻找某一段走廊使用次数最多(贪心标准),由于走廊可以同行 2 人,所以除 2,有余数再加 1 即可,即使最多的搬运次数,再乘以 10,即为最少搬运时间。

不难发现,相对应的两个房间其实是占用一段走廊的,我们可以将将房间号映射为走廊号,然后再考虑上面的解析。

代码如下:

 
import java.util.Scanner;
import static java.lang.Integer.max;
 
 
public class Main {
 
 
  public static void main(String[] args) {
 
 
      Scanner in = new Scanner(System.in);
//搬运次数
      int N;
 
//每次搬运的起点和终点
 
      int from, to;
      int maxAns = 0;
      int T;
 
      T = in.nextInt();
 
      while (T > 0) {
          T--;
          N = in.nextInt();
 
          int[] move = new int[205];
 
          for (int i = 0; i < N; i++) {
 
 
              from=in.nextInt();
              to=in.nextInt();
//将房间号映射为走廊号
              from = (from - 1) / 2;
              to = (to - 1) / 2;
//确保from<to,C++使用:swap(from, to)
              if (from > to) {
                  int temp = from;
                  from = to;
                  to = temp;
              }
 
 
//统计占用走廊情况,并统计最大值
 
              for (int j = from; j <= to; j++) {
                  move[j]++;
                  maxAns = max(maxAns, move[j]);
              }
 
 
          }
          if (maxAns % 2 == 1) maxAns = maxAns / 2 + 1;
          else maxAns /=2; //等价于/2
 
          System.out.println( maxAns * 10);
      }
  }
}

可拆分背包问题——贪心的自助餐

小 B 同学呢,想去吃自助餐,但是他是那种比较节俭的的人,既不想浪费食物,又想尽可能吃的贵一点,他于是私下里做了调查。
 小蓝餐厅的自助餐有 n 种食材,每种食材都有它的价格。
而且也能估计出每一份的重量,所以他列了一个表格。
红烧牛肉  30元    300g
油闷大虾  8元     5g
四喜丸子  4元     8g
三文鱼    5元     3g
排骨      18元    200g
麻辣兔头  20元    120g
高汤海参  40元    70g
扇贝粉丝  8元     32g
牛排      79元    240g
...
现在小 B 想知道在不超过饭量的情况下他到底最多吃多少钱的菜品。
假设自助餐厅的菜品供应同样的菜品每个人最多只能取一份。
小B的饭量假设为 C,单位为 g。
现在请你设计一个程序帮助小 B 计算他的最多吃了多少钱。

输入说明:
 第一行输入 n C(0<=n<=1000)(0<=C<=10000)
其中 n 为菜品数量,C 为小 B 的肚子容量。 
第二行输入两个数 V,W 
 第一个数 V[i] 是第 i 个菜品的价值(0<=v[i]<=10000)
 第二个数 V[i] 是第 i 个菜品的质量(0<=w[i]<=10000)
 输出解法
 
输出一行数据,表示最大的价值,保留三位小数。
输入样例: 
20 1000
1 22
2 43
123 214
12 2
123 432
21 223
22 16
77 49
34 78
34 9
43 677
21 34
23 23
12 56
332 56
21 99
123 545
389 33
12 999
23 88

输出样例:
 1204.114

运行限制:

最大运行时间:1s
最大运行内存:128M

贪心算法的最主要的特征就是无后效性,就像是自助餐这个题目,如果说吃了某一样食物,就不能吃另一个食物了,那么这就有了后效性,那就不能使用贪心算法进行解决问题了。

可拆分背包的一般解法为:

这里有 n 种不同值 v[i] 和权重 w[i] 的对象(如果选择该对象的 w[i] 可以获得值 v[i])。

你有一个容器来挑选它们。你可以根据自己的需要把它们分成任意大小的碎片。可以拾取的对象的最大重量给定为 w。请计算您能得到的最大值。

就像是这个题目,要想吃回本就要捡着贵的吃,但是贵只是一方面,人会饱,所以用价格除以质量所获的价格商才是贪心准则,应按照价格商优先进行选取。

这里因为要整体排序,所以要先创建一个类,然后自定义 cmp 函数,再使用 sort 排序。

代码如下:

package com.company;
 
import java.util.Arrays;
import java.util.Comparator;
import java.util.Scanner;
 
import static java.lang.Integer.max;
 
 
public class Main {
 
   static class Food {
 
       public double w;
       public double v;
       public double aver;
 
       Food(){
           w=0;
           v=0;
           aver=0;
       }
   }
 
   static class MyCmp implements Comparator<Food> {
 
       @Override
       public int compare(Food a, Food b) {
 
           if (a.aver > b.aver){
               return  -1;
           }
           else return 1;
 
           //助记大于号就是从大到小排序,小于号就是从小到大排序
 
       }
   }
   static Food foods[]=new Food[ 1009];
   public static void main(String[] args) {
 
       Scanner in = new Scanner(System.in);
 
       int n;
       double C;
       double Value = 0;
       n = in.nextInt();
       C = in.nextDouble();
       for (int i = 0; i < n; i++) {
           foods[i]=new Food();
           foods[i].v = in.nextDouble();
           foods[i].w = in.nextDouble();
 
           //求性价比
           foods[i].aver = foods[i].v / foods[i].w;
           //cout << foods[i].aver << endl;
 
       }
 
       //性价比排序
 
       Comparator cmp=new MyCmp();
       Arrays.sort(foods,0,n,cmp);
 
 
       //当背包(肚子)能装下所有物品(菜)时,直接输出所有的物品(菜品)价值之和
       //
       int sum = 0;
       for (int i = 0; i < n; i++) {
           sum += foods[i].w;
       }
       if (sum < C) {
           for (int j = 0; j < n; j++)
               Value += foods[j].v;
           //V = floor(V * 1000.0) / 1000.0;
           System.out.print(String.format("%.3f",Value));
           return ;
       }
 
       //当背包(肚子)不能装下所有物品时应该由性价比的顺序,选择装入的物品
 
       for (int i = 0; i < n; i++) {
           if (foods[i].w <= C) {
               Value = Value + foods[i].v;
               C = C - foods[i].w;
           } else {
               //直接将剩余的C加入即可
               Value = Value + C * foods[i].aver;
               C = 0;
           }
           if (C == 0)
               break;
       }
       //V = floor(V * 1000.0) / 1000.0;
       System.out.print(String.format("%.3f",Value));
       return ;
   }
}

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

关于贪心算法 的相关文章

  • SpringBoot (6)- 自定义Starter

    SpringBoot 6 自定义Starter 1 简介 1 1启动器starter命名 1 2什么是SpringBoot starter机制 1 3为什么要自定义starter 1 4什么时候需要创建自定义starter 1 5自动加载核
  • Matlab——图像缩放(插值法)

    实验内容 用双线性内插法实现位深度为8的灰度图像的缩放 思路 输入原图像以及缩放后图像的像素要求 宽度 高度 处理后输出新图像 我是用matlab来实现scale input img scale size 函数的 输入图像路径以及要求实现的

随机推荐

  • 排序函数c++函数模板实现

    冒泡排序 插入排序 选择排序 归并排序 快排 堆排序 冒泡排序 插入排序 选择排序 这种简单的时间复杂度是O n2 归并排序 快排 堆排序时间复杂度O nlogn include
  • 最短路的应用(G - Easy Glide );

    题意 就是到达一个点可以进行加速 加速时间3s给出了他的加速后的速度 计算从起点终点的最短距离 思路 首先把每个点都加上2这可以进行点的设置 起点为1 第一个加速点就是2 下一个就是3 设置点后进行计算 一个点都另一个点的全部时间进行计算
  • 如何评估加解密代码?

    在不深入研究代码的具体实现的情况下 如何评估加解密代码的有效性 强度 背景 迫于无赖 项目组只能安排1位新手设计一系列的加密算法 用于对本地文件和二进制代码的加密 幸运的是 对加密强度并没有过高的要求 但也希望能够有效的评估代码 并实现自动
  • Enter passphrase for key提示

    Enter passphrase for key提示 找了很多博客 都没有解决 后来通过删除密码解决了 删除方法 ssh keygen p enpty new passphrase后按回车
  • Arxiv 2307

    Retentive Network A Successor to Transformer for Large Language Models 论文 https arxiv org abs 2307 08621 代码 https github
  • Base64算法,kotlin密封接口

    密码协议 也称安全协议 指以密码学为基础的消息交换的通信协议 目的是在网络环境中提供安全服务 密码系统 指用于加密 解密的系统 柯克霍夫原则 数据的安全基于密钥而不是算法的保密 即系统的安全起决于密钥 对密钥保密 对算法公开 现代密码学设计
  • 笔试题10:Runnable接口与Thread类的区别?

    1 线程类继承自Thread则不能继承自其它类 而Runnable接口可以 2 线程类继承自Thread相对于Runnable来说 使用线程的方法更方便一些 3 实现Runnable接口的线程类的多个线程 可以更方便的访问同一变量 而Thr
  • 23种设计模式(7):中介者模式

    定义 用一个中介者对象封装一系列的对象交互 中介者使各对象不需要显示地相互作用 从而使耦合松散 而且可以独立地改变它们之间的交互 类型 行为类模式 类图 中介者模式的结构 中介者模式又称为调停者模式 从类图中看 共分为3部分 抽象中介者 定
  • .NET进阶篇07-.NET和COM

    知识需要不断积累 总结和沉淀 思考和写作是成长的催化剂 文章目录 一 COM和 NET 元数据 内存管理 接口 注册 线程 编组 二 NET客户端调用COM组件 三 COM客户端调用 NET组件 四 嵌入互操作类型 五 平台调用DllImp
  • python 利用浏览器 Cookie 模拟登录的用户访问知乎

    首先在火狐浏览器上登录知乎 然后使用火狐浏览器插件 Httpfox 获取 GET 请求的Cookie 这里注意使用状态值为 200 获取成功 的某次GET 将 Cookies 复制出来 注意这一行非常长 不要人为添加换行符 而且 Cooki
  • css 设置层级关系,css层级关系怎么设置

    在css中 可以利用z index属性来设置层级 该属性可以设置元素的堆叠顺序 拥有更高堆叠顺序的元素总是会处于堆叠顺序较低的元素的前面 语法格式 z index 数值 允许使用负值 本教程操作环境 windows7系统 CSS3 HTML
  • 刷脸支付设备深度融合多项赋能

    几年前 购物 刷脸 还只是一句饶有趣味的调侃 一转眼 靠脸吃饭 就这样成为现实 10月20日 在浙江乌镇举行的第六届世界互联网大会 金融科技 深度融合多项赋能 论坛上 中国银联联合60余家机构正式发布全新智能支付产品 刷脸付 随着10月31
  • 简单的鼠标拖拽(1)颜色渐变

  • 手把手教你协方差分析的SPSS操作

    手把手教你协方差分析的SPSS操作 2017 04 27 手把手教你协方差分析的SPSS操作 一 问题与数据 某研究将73例脑卒中患者随机分为现代理疗组 38例 和传统康复疗法组 35例 进行康复治疗 采用Fugl Meyer运动功能评分法
  • XSS Challenges闯关1-6

    第一关 靶场链接 XSS Challenges by yamagata21 Stage 1 第一关截图 翻译为中文后 选中Hint查看提示 显示非常容易 但是图中显示必须要用alert document doman 完成 我们优先考虑xss
  • fiery服务器系统安装,Fiery_SC5500_服务器安装步骤.pdf

    Fiery SC5500 服务器安装步骤 pdf Fiery SC5500 服务器安装步骤 需要光盘和数据 1 系统光盘和应用软件光盘 a EFI Fiery SC5500 系统软件 V1 1 CD 1 3 b EFI Fiery SC55
  • METRICS-BASED VERIFICATION

    原文链接 https www intrinsix com metrics based soc verification Complex SoC Verification Verification is the process by whic
  • 【ANSYS Workbench仿真】workbench启动后经常会出现ToolBox里面工具不全,应用条目缺失的现象怎么办?

    大部分都是因为License Manager的问题 处理办法如下 PS 如果每次电脑重启后都出现这个情况也很正常 只需要按照以下三步操作即可 第一步 电脑右键 gt 管理 第二步 服务 gt 找到ANSYS Inc License Mana
  • Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-reso

    springBoot部署 打包问题 解决方法 运行jar包 解决方法 在 后添加
  • 关于贪心算法

    贪心算法 Greedy algorithm 又称贪婪算法 是一种在每一步选择中都采取在当前状态下最好或最优 即最有利 的选择 从而使得问题得到全局最优解 贪心的算法的设计就是要遵循某种规则 不断地选取当前最优解的算法设计方法 贪心算法基本概