在求最优解问题的过程中,依据某种贪心标准,从问题的初始状态出发,直接去求每一步的最优解,通过若干次的贪心选择,最终得出整个问题的最优解,这种方式就是贪心算法
贪心算法不是从整体上考虑问题,它所作出的选择只是在某种意义上的局部最优解,而由问题自身的特性决定了该题运用贪心算法可以得到最优解。
如果一个问题可以用几种方式同时解决,贪心是最好的选择之一。
例题一:
活动安排问题
struct action
{
int s;//起始时间
int f;//结束时间
int index;//活动编号
}a[1000];//结构体数组
排序比较
bool cmp(action a,action b)
{
if(a.f<=b.f)
return true;
return false;
}
void select(int n,action a[],bool b[])
{
b[1]=true;
int pre=1;
for(int i=2;i<=n;++i)
if(a[i].s>=a[pre].f)
{
b[i]=true;
pre=i;
}
}
贪心选择性质是指所求问题的整体最优解可以通过一系列局部最优的选择,即贪心选择来达到。
(这是贪心算法可行的第一个基本要素,也是贪心和动态规划算法的主要区别)
(1)在动态规划算法中每步所做的选择往往依赖于相关的子问题的解,因而只有在解除相关子问题后才能做出选择。
(2)在贪心算法中,仅在当前状态下做出最好选择,即局部最优选择,然后再去解出这个选择后产生的相应的子问题。
这种策略是一种很简洁的方式,对许多问题它能产生整体最优解,但不能保证总是有效的,因为它不是对所有问题都能得到整体最优解。
利用贪心策略解题,需要解决两个问题:
(1)该题是否适用于贪心策略求解;
(2)如何选择贪心标准,以得到问题的最优/较优解。
背包问题
背包问题核心:求最高的性价比
struct bag
{
int w;//重量
int v;//价值
double c;//性价比
}a[1001];
bool cmp(bag a,bag b)//按性价比排序
{
return a.c>=b.c;
}
double pack(int n,bag a[],double c)
{
double cleft=c;//背包剩余容量
int i=0;
double b=0;//获得的价值
while(i<n&&a[i].w<cleft)//当背包还能装入物品
{
cleft-=a[i].w;
b+=a[i].v;
i++;
}
if(i<n)
b+=1.0a[i].vcleft/a[i].w;
return b;
}