贪心算法
概念
采用贪心的策略,保证每次操作都是局部最优的,从而使最后得到的结果是全局最优的。
流程
- 建立数学模型来描述问题。
- 把求解的问题分成若干个子问题。
- 对每一个子问题取得最优解。
- 把子问题的局部最优解合成得到原来的一个解。
使用贪心算法应满足的条件
-
最优子结构:问题的整体最优解包含着它的子问题的最优解
-
无后效性
经典例题
-
例题1:钱币找零问题
-
题目:指定货币和相应的数量
-
思路:每次尽可能用面值大的纸币去凑
-
代码实现:
#include<stdio.h>
const int N = 7;
int Count[N] = { 3,2,2,1,4,3,5 };
int Value[N] = { 1,2,5,10,20,50,100 };
int solve(int money)
{
int num = 0;
for (int i = N - 1; i >= 0; i--)
{
int c = money/Value[i];
if (c > Count[i]) {
c = Count[i];
}
money = money - c * Value[i];
num += c;
}
if (money > 0) num = -1;
return num;
}
int main()
{
int money;
scanf("%d", money);
int num = solve(money);
if (num != -1) printf("%d",num);
else printf("NO");
}
- 例题2:糖果问题
- 题目:一群孩子站成一排,每一个孩子有自己的评分。现在需要给这些孩子发糖果,规则是如果一个孩子的评分比自己身旁的一个孩子要高,那么这个孩子就必须得到比身旁孩子更多的糖果;所有孩子至少要有一个糖果。求解最少需要多少个糖果?
- 思路:把总问题划分为n个子问题,子问题:只要满足相邻孩子中评分高的比评分低的多一个糖果,所以先使每个孩子的糖果为1,从左到右遍历,如果右边的孩子比左边的孩子评分高,则右边的孩子为左边孩子的糖果数加一,再从右往左遍历,如果左边的孩子比右边的孩子评分高且左边孩子的糖果数不多于右边的孩子,则左边孩子的糖果数变为右边孩子糖果数加一。
- 代码实现:
#include<stdio.h>
#include<vector>
using namespace std;
int candy(vector<int>& score)
{
int size = score.size;
vector<int> num(size, 1);
for (int i = 1; i < size; i++) {
if (score[i] > score[i - 1]) {
num[i] = num[i - 1] + 1;
}
}
for (int i = size-1; i >=1; i++) {
if (score[i-1] >score[i]&& num[i - 1]<= num[i]) {
num[i-1] = num[i] + 1;
}
}
int nums=0;
for (int i = 0; i < size; i++) {
nums = nums + num[i];
}
return nums;
}
- 例题3:区间问题
- 给定多个区间,计算让这些区间互不重叠所需要移除区间的最少个数。起止相连不算重叠。
- 思路:将区间的结尾大小进行排序,每次选择最小且不重合的区间。