定义:通过逐步求局部最优(当前状态的最好选择)来导出全局最优(ps:允许的条件下贪心最快)
适用条件:具有最优子结构(一个问题的最优解包含其子问题的最优解,一个问题的最优解包含其子问题的最优解)
具有贪心选择性质(求问题的整体最优解可以通过一系列局部最优的选择,即贪心选择来达到。)
流程:
Greedy(A)
{
S={ }; //初始解集合为空集
while (not solution(S)) //集合S没有构成问题的一个解
{
x = select(A); //在候选集合A中做贪心选择
if feasible(S, x) //判断集合S中加入x后的解是否可行
S = S+{x};
A = A-{x};
}
return S;
}
(1)候选集合A:为了构造问题的解决方案,有一个候选集合A作为问题的可能解,即问题的最终解均取自于候选集合A。
(2)解集合S:随着贪心选择的进行,解集合S不断扩展,直到构成满足问题的完整解。
(3)解决函数solution:检查解集合S是否构成问题的完整解。
(4)选择函数select:即贪心策略,这是贪心法的关键,它指出哪个候选对象最有希望构成问题的解,选择函数通常和目标函数有关。
(5)可行函数feasible:检查解集合中加入一个候选对象是否可行,即解集合扩展后是否满足约束条件。
例子:
//Q1.删数问题
#include<iostream>
#include<string>
using namespace std;
main()
{
int k;
string str;
cin>>str>>k;
if(k>=str.size()) str.erase();
while(k)
{
int i;
for(i=0;i<=(str.size()-1)&&str[i]<=str[i+1];i++)
str.erase(i,1);
k--;//寻找最近下降点并删除
}
if(str.size()>1 && str[0]=='0') str.erase(0,1);//删除前导0
cout<<str<<endl;
背包问题(csdn上一篇很全的总结:https://blog.youkuaiyun.com/ling_du/article/details/41594767)
//Q2.背包问题(可拆分)
#include<iostream>
#include<algorithm>
using namespace std;
struct bag{
int w; //物品的重量
int v; //物品的价值
double c; //性价比
}a[1001]; //存放物品的数组
bool cmp(bag a, bag b){
return a.c >= b.c;
}//排序因子(按性价比降序)
//形参n是物品的数量,M是背包的容量,数组a是按物品的性价比降序排序
double knapsack(int n,bag a[], double M)//注意这里的bag a[]是传址调用
{
double Mleft=M;//背包的剩余容量
int i=0;
double b=0;//获得的价值
//当背包还能完全装入物品i
while(i<n && a[i].w<Mleft)
{
Mleft-=a[i].w;
b+=a[i].v;
i++;
}//装满背包的剩余空间
if (i<n) b += 1.0*a[i].v*Mleft/a[i].w;
return b;
}
main()
{
int n,M;
cin>>n>>M;
for(int i=0;i<n;i++) cin>>a[i].w>>a[i].v;
stable_sort(a,a+n,cmp);
double res;
res=knapsack(n,&a[1001],M);//注意这里的bag a[]是传址调用
cout<<res;
}