参考https://www.jianshu.com/p/50f1d4e0555c
贪心算法:
- 1.动态规划的一种特殊情况。
- 2.通过求局部最优解来获得整体最优解。
- 3.使用贪心算法的前提是该问题具有最优子结构。
- 4.通过可循环执行的语句实现。
- 5.一般都为逆序思维
常用于:
- 1.一般背包问题
- 2.活动安排问题
- 3.最小生成树
- 4.找零钱问题
- 5.均分纸牌问题
- 6.最大整数
- ....
实例: POJ 3253 木板切割问题
题意:
给定一个长度在[1,50000]的木板,你需要按要求切割它,每次切割都将花费等同于未切割前木板的长度的钱,
比如你要将长度21的木板切割为13和8,则需要花费21;
在将长度为13的木板切割为5 和8 ,再花费13;
所以总花费为 13+21=34;
如果先将21切割 为 16 和5 则第一次花费21
在将16切割为5和8 则再花费16
总费用为 21 + 16 =37
所以采用总费用少的方法,而本题就是求出最少花费策略;
我们应逆序思考,假如我们已知6块已经由最优策略切割好的木板, 下图表示木板,数字代表长度
1 | 2 | 3 | 4 | 5 | 6 |
两个木板肯定是由1个木板切割来的,所以切割形成了两个最短的木板的那个木板,在本图中也就是
1 | 2 |
所以切割包含了1和2的木板所花费的钱是最少的。将木板长度1保存在min1中,木板长度2保存在min2中,我们用sum保存总花费所以得出一个式子 sum+=min1+min2; 然后我们将1和2合并 得到一个长度为3的木板,并将1,2删除 得到:
3 | 3 | 4 | 5 | 6 |
此时在进行判断 找出两个最短木板,因为切割这两个木板花费最少, 我们找到 3 和 3
再将3保存在min1和min2中 并 sum+=min1+min2 并将 3 和 3 删除得到
6 | 4 | 5 | 6 |
然后我们就发现了一个规律 每次找到最小的两块木板,并将其长度累加在总费用中,并将其合并后,与剩下的木板比较,直至合并为一个木板。
那么我们如何每次都在庞大的数据中找到最小的两块木板呢?
就是用优先队列。
优先队列:
- 附带优先值的队列,优先值大的在前;
- 通俗来讲就是可对插入的数据自动排序,由大到小或由小到大;
- 头文件 #include<queue>
- 声明语句 priority_queue<int,vector<int>,greater<int> >q
- 其他操作和普通对列一致
POJ 3253参考代码 (数据大需要用long long)
#include<stdio.h>
#include<string>
#include<iostream>
#include<cmath>
#include<queue>
#include<set>
#include<algorithm>
using namespace std;
priority_queue<int,vector<int>,greater<int> >q;
int main()
{
long long n,min1,min2,a,sum=0;
cin>>n;
while(n--){
cin>>a;
q.push(a);
}
while(q.size()!=1){
min1=q.top();
q.pop();
min2=q.top();
q.pop();
q.push(min1+min2);
sum+=min1+min2;
}
cout<<sum;
while(!q.empty())
q.pop();
return 0;
}