贪心算法及几个经典例子c语言

这篇具有很好参考价值的文章主要介绍了贪心算法及几个经典例子c语言。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

贪心算法

一、基本概念:

所谓贪心算法是指,在对问题求解时,总是做出在 当前看来是最好的选择 。也就是说,不从整体最优上加以考虑,他所做出的仅是在某种意义上的 局部最优解 。

贪心算法没有固定的算法框架,算法设计的关键是贪心策略的选择。必须注意的是,贪心算法不是对所有问题都能得到整体最优解,选择的贪心策略必须具备无后效性,即某个状态以后的过程不会影响以前的状态,只与当前状态有关。

所以对所采用的贪心策略一定要仔细分析其是否满足无后效性。

二、贪心算法的基本思路:

1.建立数学模型来描述问题。

2.把求解的问题分成若干个子问题。

3.对每一子问题求解,得到子问题的局部最优解。

4.把子问题的解局部最优解合成原来解问题的一个解。

三、贪心算法适用的问题

贪心策略适用的前提是:局部最优策略能导致产生全局最优解。

实际上,贪心算法适用的情况很少。一般,对一个问题分析是否适用于贪心算法,可以先选择该问题下的几个实际数据进行分析,就可做出判断。

四、贪心算法的实现框架

从问题的某一初始解出发;

while (能朝给定总目标前进一步)

{

利用可行的决策,求出可行解的一个解元素;

}

由所有解元素组合成问题的一个可行解;

五、贪心策略的选择

因为用贪心算法只能通过解局部最优解的策略来达到全局最优解,因此,一定要注意判断问题是否适合采用贪心算法策略,找到的解是否一定是问题的最优解。

六、例题分析

下面是一个可以试用贪心算法解的题目,贪心解的确不错,可惜不是最优解。

[背包问题]有一个背包,背包容量是M=150。有7个物品,物品可以分割成任意大小。

要求尽可能让装入背包中的物品总价值最大,但不能超过总容量。

物品 A B C D E F G

重量 35 30 60 50 40 10 25

价值 10 40 30 50 35 40 30

分析:

目标函数: ∑pi最大

约束条件是装入的物品总重量不超过背包容量:∑wi<=M( M=150)

(1)根据贪心的策略,每次挑选价值最大的物品装入背包,得到的结果是否最优?

(2)每次挑选所占重量最小的物品装入是否能得到最优解?

(3)每次选取单位重量价值最大的物品,成为解本题的策略。

值得注意的是,贪心算法并不是完全不可以使用,贪心策略一旦经过证明成立后,它就是一种高效的算法。

贪心算法还是很常见的算法之一,这是由于它简单易行,构造贪心策略不是很困难。

可惜的是,它需要证明后才能真正运用到题目的算法中。

一般来说, 贪心算法的证明围绕着:整个问题的最优解一定由在贪心策略中存在的子问题的最优解得来的。

对于例题中的3种贪心策略,都是无法成立(无法被证明)的,解释如下:

(1)贪心策略:选取价值最大者。反例:

W=30

物品:A B C

重量:28 12 12

价值:30 20 20

根据策略,首先选取物品A,接下来就无法再选取了,可是,选取B、C则更好。

(2)贪心策略:选取重量最小。它的反例与第一种策略的反例差不多。

(3)贪心策略:选取单位重量价值最大的物品。反例:

W=30

物品:A B C

重量:28 20 10

价值:28 20 10

根据策略,三种物品单位重量价值一样,程序无法依据现有策略作出判断,如果选择A,则答案错误。

几个经典的例子:

一、定义

什么是贪心算法呢?所谓贪心算法是指,在对问题求解时,总是做出在当前看来最好的选择。也就是说,不从整体最优解出发来考虑,它所做出的仅是在某种意义上的局部最优解。

贪心算法不是对所有问题都能得到整体最优解,但对范围相当广泛的许多问题都能产生整体最优解或整体最优解的近似解。

贪心算法的基本思路如下:

1.建立数学模型来描述问题。

2.把求解的问题分成若干个子问题。

3.对每个子问题求解,得到每个子问题的局部最优解。

4.把每个子问题的局部最优解合成为原来问题的一个解。

实现该算法的过程:

从问题的某一初始状态出发;

while 能朝给定总目标前进一步 do

求出可行解的一个解元素;

由所有解元素组合成问题的一个可行解;

二、例题分析

[背包问题]有一个背包,背包容量是M=150。有7个物品,物品可以分割成任意大小。

要求尽可能让装入背包中的物品总价值最大,但不能超过总容量。

物品 A B C D E F G

重量 35 30 60 50 40 10 25

价值 10 40 30 50 35 40 30

记得当时学算法的时候,就是这个例子,可以说很经典。

分析:

目标函数: ∑pi最大

约束条件是装入的物品总重量不超过背包容量,即∑wi<=M( M=150)

(1)根据贪心的策略,每次挑选价值最大的物品装入背包,得到的结果是否最优?

(2)每次挑选所占重量最小的物品装入是否能得到最优解?

(3)每次选取单位重量价值最大的物品,成为解本题的策略?

贪心算法是很常见的算法之一,这是由于它简单易行,构造贪心策略简单。但是,它需要证明后才能真正运用到题目的算法中。一般来说,贪心算法的证明围绕着整个问题的最优解一定由在贪心策略中存在的子问题的最优解得来的。

对于本例题中的3种贪心策略,都无法成立,即无法被证明,解释如下:

(1)贪心策略:选取价值最大者。反例:

W=30

物品:A B C

重量:28 12 12

价值:30 20 20

根据策略,首先选取物品A,接下来就无法再选取了,可是,选取B、C则更好。

(2)贪心策略:选取重量最小。它的反例与第一种策略的反例差不多。

(3)贪心策略:选取单位重量价值最大的物品。反例:

W=30

物品:A B C

重量:28 20 10

价值:28 20 10

根据策略,三种物品单位重量价值一样,程序无法依据现有策略作出判断,如果选择A,则答案错误。

值得注意的是,贪心算法并不是完全不可以使用,贪心策略一旦经过证明成立后,它就是一种高效的算法。比如,求最小生成树的Prim算法和Kruskal算法都是漂亮的贪心算法。

[均分纸牌]有N堆纸牌,编号分别为1,2,…,n。每堆上有若干张,但纸牌总数必为n的倍数.可以在任一堆上取若干张纸牌,然后移动。移牌的规则为:在编号为1上取的纸牌,只能移到编号为2的堆上;在编号为n的堆上取的纸牌,只能移到编号为n-1的堆上;其他堆上取的纸牌,可以移到相邻左边或右边的堆上。现在要求找出一种移动方法,用最少的移动次数使每堆上纸牌数都一样多。例如:n=4,4堆纸牌分别为:① 9 ② 8 ③ 17 ④ 6 移动三次可以达到目的:从③取4张牌放到④ 再从③区3张放到②然后从②去1张放到①。

输入输出样例:4

9 8 17 6

屏幕显示:3

算法分析:设a[i]为第I堆纸牌的张数(0<=I<=n),v为均分后每堆纸牌的张数,s为最小移动次数。

我们用贪心算法,按照从左到右的顺序移动纸牌。如第I堆的纸牌数不等于平均值,则移动一次(即s加1),分两种情况移动:

1.若a[i]>v,则将a[i]-v张从第I堆移动到第I+1堆;

2.若a[i]<v,则将v-a[i]张从第I+1堆移动到第I堆。

为了设计的方便,我们把这两种情况统一看作是将a[i]-v从第I堆移动到第I+1堆,移动后有a[i]=v; a[I+1]=a[I+1]+a[i]-v.

在从第I+1堆取出纸牌补充第I堆的过程中可能回出现第I+1堆的纸牌小于零的情况。

如n=3,三堆指派数为1 2 27 ,这时v=10,为了使第一堆为10,要从第二堆移9张到第一堆,而第二堆只有2张可以移,这是不是意味着刚才使用贪心法是错误的呢?

我们继续按规则分析移牌过程,从第二堆移出9张到第一堆后,第一堆有10张,第二堆剩下-7张,在从第三堆移动17张到第二堆,刚好三堆纸牌都是10,最后结果是对的,我们在移动过程中,只是改变了移动的顺序,而移动次数不便,因此此题使用贪心法可行的。

Java源程序:

public class Greedy { public static void main(String[] args) { int n = 0, avg =0, s = 0; Scanner scanner = new Scanner(System.in); ArrayList<Integer> array = new ArrayList<Integer>(); System.out.println(“Please input the number of heaps:”); n = scanner.nextInt(); System.out.println(“Please input heap number:”); for (int i = 0; i < n; i++) { array.add(scanner.nextInt()); } for(int i = 0; i < array.size(); i ++){ avg += array.get(i); } avg = avg/array.size(); System.out.println(array.size()); System.out.println(avg); for(int i = 0; i < array.size()-1; i ++){ s++; array.set(i+1, array.get(i+1)+array.get(i)-avg); } System.out.println(“s:” + s); } }

利用贪心算法解题,需要解决两个问题:

一是问题是否适合用贪心法求解。我们看一个找币的例子,如果一个货币系统有三种币值,面值分别为一角、五分和一分,求最小找币数时,可以用贪心法求解;如果将这三种币值改为一角一分、五分和一分,就不能使用贪心法求解。用贪心法解题很方便,但它的适用范围很小,判断一个问题是否适合用贪心法求解,目前还没有一个通用的方法,在信息学竞赛中,需要凭个人的经验来判断。

二是确定了可以用贪心算法之后,如何选择一个贪心标准,才能保证得到问题的最优解。在选择贪心标准时,我们要对所选的贪心标准进行验证才能使用,不要被表面上看似正确的贪心标准所迷惑,如下面的例子。

[最大整数]设有n个正整数,将它们连接成一排,组成一个最大的多位整数。

例如:n=3时,3个整数13,312,343,连成的最大整数为34331213。

又如:n=4时,4个整数7,13,4,246,连成的最大整数为7424613。

输入:n

N个数

输出:连成的多位数

算法分析:此题很容易想到使用贪心法,在考试时有很多同学把整数按从大到小的顺序连接起来,测试题目的例子也都符合,但最后测试的结果却不全对。按这种标准,我们很容易找到反例:12,121应该组成12121而非12112,那么是不是相互包含的时候就从小到大呢?也不一定,如12,123就是12312而非12123,这种情况就有很多种了。是不是此题不能用贪心法呢?

其实此题可以用贪心法来求解,只是刚才的标准不对,正确的标准是:先把整数转换成字符串,然后在比较a+b和b+a,如果a+b>=b+a,就把a排在b的前面,反之则把a排在b的后面。

java源程序:

public static void main(String[] args){ String str = “”; ArrayList<String> array = new ArrayList<String>(); Scanner in = new Scanner(System.in); System.out.println(“Please input the number of data:”); int n = in.nextInt(); System.out.println(“Please input the data:”); while (n– > 0) { array.add(in.next()); } for(int i = 0; i < array.size(); i ++) for(int j = i + 1; j < array.size(); j ++){ if((array.get(i) + array.get(j)).compareTo(array.get(j) + array.get(i)) < 0){ String temp = array.get(i); array.set(i, array.get(j)); array.set(j, temp); } } for(int i = 0; i < array.size(); i ++){ str += array.get(i); } System.out.println(“str=:”+str); } }

贪心算法所作的选择可以依赖于以往所作过的选择,但决不依赖于将来的选择,也不依赖于子问题的解,因此贪心算法与其他算法相比具有一定的速度优势。如果一个问题可以同时用几种方法解决,贪心算法应该是最好的选择之一。文章来源地址https://www.toymoban.com/news/detail-789795.html

到了这里,关于贪心算法及几个经典例子c语言的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 算法提高:贪心策略的11个经典题目

    目录 字典序最小 零钱问题 股票问题(最多持有一支,可以买卖无限次) 小船过河 任务调度器 摆动序列 最小区间 跳跃游戏 II 分糖果 通配符匹配 拼接最大数 题目 给定一个由字符串组成的数组strs,必须把所有的字符串拼接起来,返回所有拼接结果中,字典序最小的结果。

    2024年02月13日
    浏览(47)
  • class092 贪心经典题目专题4【左程云算法】

    2024-4-23 14:00:04 以下内容源自《【左程云算法】》 仅供学习交流使用 禁止其他平台发布时删除以下此话 本文首次发布于CSDN平台 作者是CSDN@日星月云 博客主页是https://jsss-1.blog.csdn.net 禁止其他平台发布时删除以上此话 算法讲解092【必备】贪心经典题目专题4 先占个位 迎着日光

    2024年04月26日
    浏览(39)
  • 一道经典的小学数学题,和它背后的贪心算法(35)

    小朋友们好,大朋友们好! 我是猫妹,一名爱上Python编程的小学生。 欢迎和猫妹一起,趣味学Python。 今日主题 这个五一小长假,你玩得怎么样? 今天,咱们先做一道经典的小学数学题,抛砖引玉,然后了解下贪心算法。 一个地主临终前留下了遗嘱,将自己的11头牛分给三

    2024年02月02日
    浏览(42)
  • 【经典LeetCode算法题目专栏分类】【第5期】贪心算法:分发饼干、跳跃游戏、模拟行走机器人

    《博主简介》 小伙伴们好,我是阿旭。专注于人工智能AI、python、计算机视觉相关分享研究。 ✌ 更多学习资源,可关注公-仲-hao:【阿旭算法与机器学习】,共同学习交流~ 👍 感谢小伙伴 们点赞、关注! class   Solution :      def   findContentChildren ( self ,  g :  List [ int ],  s

    2024年02月04日
    浏览(55)
  • python - leetcode - 424. 替换后的最长重复字符【经典题解 - 贪心滑动窗口算法】

    描述: 给你一个字符串 s 和一个整数 k 。你可以选择字符串中的任一字符,并将其更改为任何其他大写英文字符。该操作最多可执行 k 次。 在执行上述操作后,返回包含相同字母的最长子字符串的长度。 示例 1: 示例 2: 提示: 1 = s.length = 105 s 仅由大写英文字母组成 0 =

    2024年02月16日
    浏览(48)
  • 计算机视觉的几个经典算法 —— 最小二乘法 + RANSAC + 哈希算法(附DCT) + 图像聚类算法

    在了解最小二乘法之前,我们有必要先说说线性回归,所谓线性回归我们最常见的例子y=2x这个一元线性回归方程中,斜率2就是回归系数,它表示的是x变动时,y与之对应的关系,而线性回归就是表示一些离散的点在总体上是最逼近某一条直线的 这跟最小二乘法有啥关系呢?

    2024年02月08日
    浏览(44)
  • 【详解】KMP算法——多图,多例子(c语言)

    目录 前言 1.KMP算法是什么? 2.为什么需要KMP算法? 2.1主串找字串 2.2暴力求解 3.KMP准备工作 3.1字符串的前后子串 3.2最大前后相等子串 3.3最大前后相等子串练习 4.KMP算法 4.1简看KMP算法 5 Next数组      5.1j该回溯的位置  5.2学会计算Next数组            5.3用数学表示next数组(

    2023年04月23日
    浏览(41)
  • (C语言贪心算法)0/1背包问题

    已知一个载重为M的背包和n件物品,物品编号从0到n-1。第i件物品的重量为 wi,若将第i种物品装入背包将获益pi,这里,wi0,pi0,0=in。所谓0/1背包问题是指在物品不能分割,只能整件装入背包或不装入的情况下,求一种最佳装载方案使得总收益最大。 第 1 行中有 2 个正整

    2024年02月08日
    浏览(41)
  • 基于贪心算法的TSP问题(c语言)

     data.txt 代码   

    2024年02月11日
    浏览(44)
  • 【物联网】C语言实现PID算法:原理、例子和代码详解

    PID(Proportional-Integral-Derivative)是一种常用的控制算法,广泛应用于工业控制系统中。本文将详细介绍PID算法的原理,并给出一个具体的例子和相应的C语言代码实现。 PID算法通过不断调整输出值,使得系统的实际值逐渐接近期望值。它由三个部分组成: 比例(P)、积分(

    2024年02月12日
    浏览(42)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包