贪心法的基本概念
(1)贪心法要解决的问题是这样的一类问题,有n个输入,问题的解由这n个输入的某个子集组成,同时要求这个子集必须满足某些事先给定的条件,这些必须满足的条件称为约束条件。
(2)满足约束条件的子集,被称为可行解。
(3)为了衡量可行解的优劣,事先也给出一定的标准,这些标准一般以函数的形式给出,这些函数被称为目标函数。
(4)那些使目标函数取极值的可行解,称为最优解。
选择能产生问题最优解的最优量度标准是使用贪心法设计求解的核心问题,我们在求解问题利用贪心法时需要考虑的最重要的就是量度标准。选择最优的度量标准可以有效地使用贪心方法进行设计求解。
背包问题:注意这个是非0,1问题的背包问题
1、问题描述
给定n个物品和一个容量为M的背包,物品i的重量是wi,其效益值是pi ,xi为装入系数,背包问题就是如何选择装入背包的物品,使得装入背包中物品的总的效益值(Σpixi)最大。
2.算法设计
考虑下列情况下的背包问题:n=3,M=20,(p1,p2,p3)=(25,24,15),(w1,w2,w3)=(18,15,10)
(1)随意装
(2)选择效益值最大的物品先装
(3)选择重量最轻的物品先装
(4)选择单位重量效益值最大的物品先装
通过这四种方法进行装入背包我们是可以发现第4种是我们可以得到效益最高的方法,这是因为我们背包问题的实际上量度标准就是单位重量效益。这个例子告诉我们选择好的优秀的量度标准在背包问题中是很重要的事情。
算法的描述:
在这里面就是如果背包的剩余容量是大于物品的重量的那么这个物品是可以放下的这个的解向量就是1继续进行这个循环,但如果背包的剩余容量是小于物品的重量那么就跳出这个循环将解向量设为剩余重量除以这个物品重量。例如背包剩余4KG但是物品有5KG那么就将物品放下4/5部分即解向量就是4/5。
举例说明 背包问题,M=60,P=(40,20,30,28,24,72,12), W=(18,12,20,28,4,16,8)
代码如下:
#include<stdio.h>
int main(){
//前期的准备工作
int m=60;//背包的总容量
double sum=0.00;//总效益
double p[7]={40.00,20.00,30.00,28.00,24.00,72.00,12.00};//每个物品的效益
double w[7]={18.00,12.00,20.00,28.00,4.00,16.00,8.00};//每个物品的重量
double a[7];//单位重量的效益数组
for(int i=0;i<7;i++)
a[i]=p[i]/w[i];
//利用冒泡排序将单位重量效益排好顺序以及将每个物品重量和效益也相对应
for(int n=0;n<7;n++)
{
for(int i=0;i<6;i++)
{
if(a[i+1]<a[i])
{
double b;
b=a[i];a[i]=a[i+1];a[i+1]=b;
double c;
c=w[i];w[i]=w[i+1];w[i+1]=c;
double d;
d=p[i];p[i]=p[i+1];p[i+1]=d;
}
}
}
//贪心算法
int k;
for(k=6;k>=0;k--)
{
if(m>w[k])
{
printf("重量为%lf的物品装了1件\n",w[k]);
m=m-w[k];
sum=sum+p[k];
}
else
break;
}
printf("重量为%lf的物品装了%.2f件\n",w[k],m/w[k]);
sum=sum+p[k]*m/w[k];
k--;
for(k;k>=0;k--)
printf("重量为%lf的物品装了0件\n",w[k]);
printf("总效益为%lf\n",sum);
}
运行结果:
时间复杂度这主要是在排序的部分有时间复杂度: O(nlogn)
这里注意排序有很多优秀的算法可以有快速排序或者归并排序等等,所以该算法的时间复杂度是O(nlogn)。但是我个人一点书写习惯所书写代码用到的是冒泡排序,所以我的代码的时间复杂度为O(n*n)。这里做个区分