贪心算法讲解

本文介绍了贪心算法的概念、基本思路及其实现框架,并通过经典的背包问题详细解释了如何选择有效的贪心策略,以达到全局最优解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

贪心算法

、概念

所谓贪心算法是指,在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,他所做出的仅是在某种意义上的局部最优解。贪心算法没有固定的算法框架,算法设计的关键是贪心策略的选择。必须注意的是,贪心算法不是对所有问题都能得到整体最优解,选择的贪心策略必须具备无后效性,即某个状态以后的过程不会影响以前的状态,只与当前状态有关。虽然贪心算法不能对所有问题都得到整体最优解,但对许多问题它能产生整体最优解。如单源最短路经问题,最小生成树问题等。在一些情况下,即使贪心算法不能得到整体最优解,其最终结果却是最优解的很好近似。所以对所采用的贪心策略一定要仔细分析其是否满足无后效性。

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

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

贪心算法适用的问题

贪心策略适用的前提是:局部最优策略能导致产生全局最优解。实际上贪心算法适用的情况很少。一般,对一个问题分析是否适用于贪心算法,可以先选择该问题下的几个实际数据进行分析,就可做出判断。

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

动态规划算法通常以自底向上的方式解各子问题,而贪心算法则通常以自顶向下的方式进行,以迭代的方式作出相继的贪心选择,每作一次贪心选择就将所求问题简化为规模更小的子问题。 

对于一个具体问题,要确定它是否具有贪心选择性质,必须证明每一步所作的贪心选择最终导致问题的整体最优解。

贪心算法的实现框架

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

while (能朝给定总目标前进一步)
{
利用可行的决策,求出可行解的一个解元素;
}

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

五、贪心例题(贪心问题解决背包问题)

 一、【经典实例:】(背包问题)

    给定n个物品和一个容量为C的背包,物品i的重量是Wi,其价值为Vi,背包问题是如何选择入背包的物品,使得装入背包的物品的总价值最大,注意和0/1背包的区别,在背包问题中可以将物品的一部分装入背包,但不能重复装入。

 二、【想法:】

    用贪心法求解背包问题的关键是如何选定贪心策略,使得按照一定的顺序选择每个物品,并尽可能的装入背包,知道背包装满。至少有三种看似合适的贪心策略。

  1. 选择价值最大的物品,因为这可以尽可能快的增加背包的总价值,但是,虽然每一步选择获得了背包价值的极大增长,但背包容量却可能消耗的太快,使得装入背包的物品个数减少,从而不能保证目标函数达到最大。
  2. 选择重量最轻的物品,因为这可以装入尽可能多的物品,从而增加背包的总价值。但是,虽然每一步选择使背包的容量消耗的慢了,但背包的价值却没能保证迅速的增长,从而不能保证目标函数达到最大。
  3. 以上两种贪心策略或者只考虑背包价值的增长,或者只考虑背包容量的消耗,而为了求得背包问题的最优解,需要在背包价值增长和背包容量消耗二者之间寻找平衡。正确的贪心策略是选择单位重量价值最大的物品。

    例如:有三个物品,其重量分别为{20,30,10},价值分别为{60,120,50},背包的容量为50,应用三种贪心策略装入背包的物品和获得的价值如下图所示:

        

     三、【算法:】

    设背包容量为C,共有n个物品,物品重量存放在数组W[n]中,价值存放在数组V[n]中,问题的解存放在数组X[n]中,贪心法求解背包问题的算法如下:

算法:贪心法求解背包问题

输入:背包的容量C,物品重量W[n],物品价值V[n]

输出:数组X[n]

  1. 改变数组WV的排列顺序,使其按单位重量价值V[i]/W[i]降序排列;
  2. 将数组X[n]初始化为0
  3. i=0
  4. 循环直到(W[i]>C

    4.1   将第i个物品放入背包:X[i]=1;

    4.2    C=C-W[i];

    4.3    i++;

  1. X[i]=C/W[i]

   五、【算法实现:】

    实现函数KnapSacks实现贪心法求解背包问题,简单起见,假设物品已按单位重量降序排列,算法C++语言描述如下:


int KnapSack (int W[],int V[],int N,int C)
{
	double X[10]={0};
	int maxValue=0;
	for(int i=0;W[i]<C;i++)
	{
		X[i]=1;
		maxValue+=V[i];
		C=C-W[i];
		
	X[i]=(double)C/W[i];
	maxValue+=X[i]*V[i];
	return maxValue;
	}
}


     六、【总结:】

    贪心法并不是从整体最优考虑,它所做出的选择只是在某种意义上的局部最优。贪心算法对于大部分的优化问题都能产生最优解,但不能总获得整体最优解,通常可以获得近似最优解。






### 关于C/C++中的贪心算法 #### 贪心算法简介 贪心算法是一种在每一步选择中都采取当前状态下最优的选择,从而希望最终能够得到全局最优解的算法。这种策略并不总是能获得最优化的结果,但在某些情况下可以有效地解决问题。 #### 实现方式 为了实现贪心算法,在编程语言如C/C++里通常会遵循以下模式: - **定义数据结构**:根据具体问题设计合适的数据存储形式。 - **初始化变量**:设置必要的初始条件和边界值。 - **迭代过程**:通过循环逐步处理每一个子问题,并做出局部最优决策。 - **终止条件判断**:当满足特定结束标准时停止计算并返回结果。 #### 示例代码展示 下面给出一个简单的例子来说明如何利用贪心法解决硬币找零问题(假设存在无限数量的各种面额的钱币),这里采用的是C++版本[^1]: ```cpp #include <iostream> using namespace std; void findMinCoins(int coins[], int m, int V) { // Table to store results of subproblems int table[V + 1]; // Base case (If given value is 0) table[0] = 0; // Initialize all table values as Infinite for (int i = 1; i <= V; i++) table[i] = INT_MAX; // Compute minimum coins required for all values from 1 to V for (int i = 1; i <= V; i++) { // Go through all coins smaller than i for (int j = 0; j < m; j++) if (coins[j] <= i) { int sub_res = table[i - coins[j]]; if (sub_res != INT_MAX && sub_res + 1 < table[i]) table[i] = sub_res + 1; } } // Print result cout << "Minimum number of coins needed: "; if(table[V]==INT_MAX){ cout<<"Not Possible"; }else{ cout<<table[V]; } } // Driver program to test above function int main() { int coins[] = {9, 6, 5, 1}; int m = sizeof(coins)/sizeof(coins[0]); int V = 11; findMinCoins(coins, m, V); return 0; } ``` 此段代码展示了怎样运用动态规划的思想配合贪心原则去寻找最小数量货币组合以凑齐指定金额V的方法[^2]。 #### 输入/输出注意事项 值得注意的一点是在读取输入文件或者字符串流的时候要注意不同操作系统下的换行符差异。对于Windows平台而言,“回车加换行”的组合(\r\n),而在Unix/Linux/MacOS下则是单独的一个换行字符(\n)[^4]。因此建议使用较为通用的方式来进行I/O操作,比如`cin>>variable` 或者 `getline(cin,line)` 来避免潜在兼容性问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值