算法与程序设计之贪心算法

文章目录

  • 实例问题
    • 分析
    • 根据分析给出代码
  • 贪心算法
    • 贪心选择
    • 最优子结构
    • 贪心算法的一般求解过程

实例问题

首先我们先来看一个算法题,由这个题来理解贪心算法
题目描述:
一只袋鼠要从河这边跳到河对岸,河很宽,但是河中间打了很多桩子,每隔一米就有一个,每个桩子上都有一个弹簧,袋鼠跳到弹簧上就可以跳的更远,每个弹簧力量不同,用一个数字代表它的力量,如果弹簧力量为5,就代表袋鼠下一跳最多能够跳5米,如果为0,就会陷进去无法继续跳跃,河流一共N米宽,袋鼠初始位置就在第一个弹簧上面,要跳到最后一个弹簧之后就算过河了,给定每个弹簧的力量,求袋鼠最少需要多少跳能够到达对岸。如果无法到达输出-1;

分析

问题要求是最少多少跳可以到达对岸?典型的最优解问题,在求解最优解问题的时候,贪心算法往往是我们的一个思路,但并不是所有的最优解问题都可以用贪心算法,这有一定的判断条件。

先给出一个数组 [2 3 1 1 1]
从2开始先后跳,题目要求用最少的跳数。我们只要保证每次跳都能尽可能的远,这样得到的跳数才能尽可能的小,思路是对的,但是如果从前面开始分析的话。
给出的数组中如果每次都跳当前桩子的最大值,并不能得到最小的跳数。
既然思路是对的,我们换个方向,从后往前分析,从后面找能跳到对岸的最远距离的桩子第一次找是 4 号下标(下标从0开始),能跳到对岸,且里对岸最远,然后以4号下标作为对岸,往前找能跳到4号下标的且离4号最远的桩子,这时候是1号下标的3,依次类推,因为每次都是找到最大距离,所以经历的跳数是最少的。

根据分析给出代码

int fun(int *arr,int len)
{
	//如果河的长度为0 则返回0
	if(len == 0)
	{
		return 0;
	}
	int i = len-1;  //i开始为离对岸最近的桩子的位置
	int m = 1;     //记录到河对岸的距离
	//seat 记录 能跳到对岸且距离对岸最远的位置
	int seat = -1;
	for(i = len-1; i >= 0; i--)
	{
		if(arr[i]-m >= 0)
		{
			seat = i;
		}
		m++;
	}
	//当所有的位置都跳不到对岸的时候,则返回-1
	if(seat == -1)  { return -1; }
	
	//否则的话,将seat 位置 当作岸,迭代向前查找能跳到seat 位置的离seat位置最远的桩子
	count = fun(arr,seat);
	//如果所有桩子都跳不到seat 位置,则说明到不了对岸
	if(count == -1)  { return -1; }
	//否则返回到从开始到 seat 的跳数加一
	return count+1;
}

这里用了一个递归,简化了代码,https://blog.csdn.net/qq_43390943/article/details/88915908
如果不理解,这里有关于递归的讲解

贪心算法

贪心选择

贪心选择是指所求问题的整体最优解可以通过一系列局部最优的选择,即贪心选择来达到。用数学归纳法证明,通过每一步贪心选择,最终可得到问题的一个整体最优解。

最优子结构

当一个问题的最优解包含其子问题的最优解时,称此问题具有最优子结构性质。运用贪心策略在每一次转化时都取得了最优解。问题的最优子结构性质是该问题可用贪心算法或动态规划算法求解的关键特征。贪心算法的每一次操作都对结果产生直接影响,而动态规划则不是。贪心算法对每个子问题的解决方案都做出选择,不能回退;动态规划则会根据以前的选择结果对当前进行选择,有回退功能。动态规划主要运用于二维或三维问题,而贪心一般是一维问题

贪心算法的一般求解过程

1、建立数学模型来描述问题;
2、把求解的问题分成若干个子问题;
3、对每一子问题求解,得到子问题的局部最优解;
4、把子问题的解局部最优解合成原来解问题的一个解。

你可能感兴趣的:(算法)