您的位置:首页 > 编程语言 > C语言/C++

黑马程序员--C语言算法之01背包问题

2014-07-23 01:16 295 查看
----------------------ASP.Net+Unity开发.Net培训、期待与您交流!
----------------------

0-1背包问题
描述
现在有很多物品(它们是可以分割的),我们知道它们每个物品的单位重量的价值v和重量w(1<=v,w<=10);如果给你一个背包它能容纳的重量为m(10<=m<=20),你所要做的就是把物品装到背包里,使背包里的物品的价值总和最大。
输入
第一行输入一个正整数n(1<=n<=5),表示有n组测试数据;

随后有n测试数据,每组测试数据的第一行有两个正整数s,m(1<=s<=10);s表示有s个物品。接下来的s行每行有两个正整数v,w。
输出
输出每组测试数据中背包内的物品的价值和,每次输出占一行。
样例输入

1
3 15
5 10
2 8
3 9

样例输出

65

一、贪心算法:
用贪心法设计算法的特点是一步一步地进行,根据某个优化测度(可能是目标函数,也可能不是目标函数),每一步上都要保证能获得局部最优解。每一步只考虑一个数据,它的选取应满足局部优化条件。若下一个数据与部分最优解连在一起不再是可行解时,就不把该数据添加到部分解中,直到把所有数据枚举完,或者不能再添加为止。

程序示例:

#include<stdio.h>

#definemax(a,b) a>b?a:b

intmain()

{

int n,s,m,v,w,i,j,k;

scanf("%d",&n);

while(n--)

{

int DP[25]={0};

scanf("%d %d",&s,&m);

for(i=0;i<s;i++)

{

scanf("%d%d",&v,&w);

for(k=0;k<w;k++)

for(j=m;j>0;j--)

DP[j]=max(DP[j-1]+v,DP[j]);

}

printf("%d\n",DP[m]);

}

}

二、递归算法

1、0- 1 背包问题如果采用递归算法来描述则非常清楚明白, 它的算法根本思想是假设用布尔函数knap( s, n) 表示n 件物品放入可容质量为s 的背包中是否有解( 当knap 函数的值为真时,说明问题有解,其值为假时无解) . 我们可以通过输入s和n 的值, 根据它们的值可分为以下几种情况讨论:

(1) 当s= 0时可知问题有解, 即函数knap( s, n) 的值为true;

(2) 当s<0 时这时不可能,所以函数值为false;

(3) 当输入的s>0 且n< 1 时即总物品的件数不足1, 这时函数值为false,只有s> 0 且n\1 时才符合实际情况,这时又分为两种情况: ( 1) 选择的一组物体中不包括Wn则knap( s, n) 的解就是knap(s, n- 1) 的解. ( 2) 选择的一组物体中包括Wn 则knap( s, n) 的解就是knap( s- Wn, n- 1)
的解. 这样一组Wn 的值就是问题的最佳解.这样就将规模为n 的问题转化为规模为n- 1 的问题. 综上所述0- 1 背包问题的递归函数定义为:

knap(s, n) =∕true,s= 0

︳false, s< 0

︳false, s> 0 且n< 1

\knap( s, n- 1) 或knap( s- Wn, n- 1) ,s> 0 且n>= 1

采用此法求解0- 1 背包问题的时间复杂度为O( n) . 上述算法对于所有物品中的某几件恰能装满背包时能准确求出最佳解. 但一般情况是对于某一些物品无论怎么装都不能装满背包, 必须要按背包的最大容量来装. 如物品件数为4, 其质量分别为:10, 2, 5, 4, 背包的容量为20, 则这四件物品无论怎么放都不能恰好装满背包, 但应能最大限度装, 即必须装下10,5,
4 这三件物品, 这样就能得到最大质量19. 对于这种装不满的背包它的解决办法是这样的: 按所有物品的组合质量最大的方法装背包, 如果还装不满,则我们可以考虑剩余空间能否装下所有物品中最小的那件, 如果连最小的都装不下了则说明这样得到的解是最佳解, 问题解决. 这样我们必须先找出所有n件物品中质量最小的那件( 它的质量为Min) , 但是为了问题的解决我们不能增加运算次数太多, 并且必须运用上述递归函数. 那么我们可通过修改s 的值即背包的容量, 从背包容量s 中减去k( 它的值是从0 到Min- 1 之间的一个整数值)
, 再调用递归函数. 当k= 0 时即能装满背包, 其它值也能保证背包能最大限度装满, 这样所有问题都解决了.

2、程序示例

#include"stdio.h"

inta[10][2],w;

intknap(int sum,int i)

{

if(sum+a[i][1]>=w)

return(w-sum)*a[i][0];

else

{

sum+=a[i][1];

return a[i][0]*a[i][1]+ knap(sum,++i);

}

}

intmain()

{

int T,i,j,t,n;

scanf("%d",&T);

while(T--)

{

scanf("%d%d",&n,&w);

for(i=0;i<n;i++)

{

scanf("%d%d",&a[i][0],&a[i][1]);

}

for(i=0;i<n-1;i++)

for(j=i+1;j<n;j++)

if(a[i][0]<a[j][0])

{

t=a[i][0]; a[i][0]=a[j][0];a[j][0]=t;

t=a[i][1]; a[i][1]=a[j][1];a[j][1]=t;

}

printf("%d\n", knap(0,0));

}

}

----------------------ASP.Net+Unity开发.Net培训、期待与您交流!
----------------------

详细请查看:www.itheima.com
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: