贪心算法总是作出在当前看来最好的选择。也就是说贪心算法并不从整体最优考虑,它所作出的选择只是在某种意义上的局部最优选择。当然,希望贪心算法得到的最终结果也是整体最优的。虽然贪心算法不能对所有问题都得到整体最优解,但对许多问题它能产生整体最优解。如单源最短路经问题,最小生成树问题等。在一些情况下,即使贪心算法不能得到整体最优解,其最终结果却是最优解的很好近似。
从许多可以用贪心算法求解的问题中看到这类问题一般具有2个重要的性质:贪心选择性质和最优子结构性质。
1)所谓贪心选择性质是指所求问题的整体最优解可以通过一系列局部最优的选择,即贪心选择来达到。这是贪心算法可行的第一个基本要素,也是贪心算法与动态规划算法的主要区别。动态规划算法通常以自底向上的方式解各子问题,而贪心算法则通常以自顶向下的方式进行,以迭代的方式作出相继的贪心选择,每作一次贪心选择就将所求问题简化为规模更小的子问题。
2)对于一个具体问题,要确定它是否具有贪心选择性质,必须证明每一步所作的贪心选择最终导致问题的整体最优解。
当一个问题的最优解包含其子问题的最优解时,称此问题具有最优子结构性质。问题的最优子结构性质是该问题可用动态规划算法或贪心算法求解的关键特征。
例如:背包问题和0-1背包问题,
0-1背包问题:给定n种物品和一个背包,物品i的重量为wi,相应价值为vi,背包容量为V,问如何选择装入背包的物品,可使得其装入背包中物品总价值最大?
在0-1背包问题中,每种物品都只有取和不取这2种选择,每一种物品不能只装入一部分,也不能重复装入。最后背包可能装满了,也可能没有满。
背包问题:给定n种物品和一个背包,物品i的重量为wi,相应价值为vi,背包容量为V,问如何选择装入背包的物品,可使得其装入背包中物品总价值最大?
在这个问题中,可以选整个物品,也可以选择物品的一部分,还可以不选,最后背包一定装满的。
看个例子贪心算法的例子,hdu 1009 FatMouse' Trade
题意:老鼠有m磅奶酪,去和猫进行交易,换取自己喜欢吃的豆子,每一个房间中包含j[i]磅豆子并且这j[i]磅豆子要求F[i]磅奶酪,老鼠可以用F[i]*a%的奶酪取换取第i个房间的J[i]*a%磅的豆子,求老鼠可以获得豆子的最大价值。
代码如下:
思路:先根据单位价值排序,在贪心求解
#include<iostream>
#include<algorithm>
using namespace std;
int n,m;
typedef struct
{
int j;
int f;
}Node;
Node arr[1005];
bool cmp(Node a,Node b)
{
return (a.f*1.0/a.j) < (b.f*1.0/b.j);
}
int main()
{
while(scanf("%d %d",&n,&m))
{
if(n==-1&&m==-1)
{
break;
}
else
{
for(int i=0;i<m;i++)
scanf("%d %d",&arr[i].j,&arr[i].f);
sort(arr,arr+m,cmp);
double sum=0.0;
for(int i=0;i<m;i++)
{
if(n>=arr[i].f)
{
sum+=arr[i].j;
n-=arr[i].f;
}
else
{
sum+=arr[i].j*(n*1.0/arr[i].f);
break;
}
}
printf("%5.3lf\n",sum);
}
}
return 0;
}
再看个 0-1背包例子,hdu 2602 BoneCollector,典型的01-背包
题意:给一个头骨背包容量V,有n个头骨,第i个头骨重量为wi,价值为vi,问如何装入背包使得背包价值最大?该问题中头骨是不能部分装入背包的。
Dp状态方程dp[i] = max(dp[i],dp[I - wi] + vi) //dp[i]表示容量为i时获得的头骨的最大价值
代码如下:
#include <iostream>
using namespace std;
#define MAXSIZ 1100
int cost[MAXSIZ];
int weight[MAXSIZ];
int n,v;
int dp[MAXSIZ];
int max(int a, int b)
{
return a>b?a:b;
}
int main()
{
int T;
scanf("%d",&T);
while ( T--)
{
scanf("%d%d", &n, &v);
for (int i =1;i <= n;i++)
{
scanf("%d",&weight[i]);
}
for (int i =1;i <= n;i++)
{
scanf("%d",&cost[i]);
}
memset(dp, 0,sizeof(dp));
for (int i =1; i <= n;i++)
{
for(int j= v; j >= cost[i];j--)
{
dp[j]= max(dp[j], dp[j-cost[i]] + weight[i]);
}
}
printf("%d\n",dp[v]);
}
return 0;
}