C++ 贪心算法(一)

基本概念:
在求最优解问题的过程中,依据某种贪心标准,从问题的初始状态出发,直接去求每一步的最优解,通过若干次的贪心选择,最终得出整个问题的最优解,这种求解方法就是贪心算法。
从贪心算法的定义可以看出,贪心算法不是从整体上考虑问题,它所做出的选择只是在某种意义上的局部最优解,而由问题自身的特性决定了该题运用贪心算法可以得到最优解。
如果一个问题可以同时用几种方法解决,贪心算法应该是最好的选择之一。
贪心算法是一种在每一步选择中都采取在当前状态下最好或最优的选择,希望得到结果是最好或最优的算法。
贪心算法是一种能够得到某种度量意义下的最优解的分级处理方法,通过一系列的选择得到一个问题的解,而它所做的每一次选择都是当前状态下某种意义的最好选择。即希望通过问题的局部最优解求出整个问题的最优解。
这种策略是一种很简洁的方法,对许多问题它能产生整体最优解,但不能保证总是有效,因为它不是对所有问题都能得到整体最优解。

然而利用贪心策略解题,需要解决两个问题:
(1)该题是否适合于用贪心策略求解;
(2)如何选择贪心标准,以得到问题的最优/较优解。

贪心选择性质是指所求问题的整体最优解可以通过一系列局部最优的选择,即贪心选择来达到。
当一个问题的最优解包含其子问题的最优解时,称此问题具有最优子结构性质。
运用贪心策略在每一次转化时都取得了最优解。问题的最优子结构性质是该问题可用贪心算法或动态规划算法求解的关键特征。

贪心算法的每一次操作都对结果产生直接影响。
贪心算法对每个子问题的解决方案都做出选择,不能回退。

求解过程如下:
使用贪心算法求解问题应该考虑如下几个方面:
(1)候选集合A:为了构造问题的解决方案,有一个候选集合A作为问题的可能解,即问题的最终解均取自于候选集合A。
(2)解集合S:随着贪心选择的进行,解集合S不断扩展,直到构成满足问题的完整解。
(3)解决函数solution:检查解集合S是否构成问题的完整解。
(4)选择函数select:即贪心策略,这是贪心法的关键,它指出哪个候选对象最有希望构成问题的解,选择函数通常和目标函数有关。
(5)可行函数feasible:检查解集合中加入一个候选对象是否可行,即解集合扩展后是否满足约束条件。

上述就是贪心算法中的的基本概念,然而贪心算法的运用才是重中之重,下面几道例题,希望会有帮助。
贪心算法的经典问题就是背包问题。

给定一个载重量为M的背包,考虑n个物品,其中第i个物品的重量 ,价值wi (1≤i≤n),要求把物品装满背包,且使背包内的物品价值最大。
有两类背包问题(根据物品是否可以分割),如果物品不可以分割,称为0—1背包问题(动态规划);如果物品可以分割,则称为背包问题(贪心算法)。

下面分享此题的完整代码:

#include<iostream>
#include<algorithm>
using namespace std;
struct bag
{
	int w;
	int v;
	double c;
}a[1001];
int main()
{
	int cleft, b = 0, n, m, i, j = 0;
	cin >> n;
	for (i = 0; i < n; ++i)
	{
		cin >> a[i].w;
		cin >> a[i].v;
		a[i].c = a[i].w /a[i]. v;
	}
	for (i = 0; i < n-1; ++i)
	{
		if (a[i].c < a[i + 1].c)  swap(a[i].c, a[i + 1].c);
	}
	cin >> m;
	cleft = m;
	while (j < n&&a[j].w < cleft)
	{
		cleft -= a[j].w;
		b += a[j].v;
		j++;
	}
	if (j < n) b += 1.0*a[j].v*cleft / a[i].w;
	cout << b;
	return 0;
}
发布了90 篇原创文章 · 获赞 15 · 访问量 3164

猜你喜欢

转载自blog.csdn.net/qq_43656233/article/details/88543042