Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2278503
  • 博文数量: 668
  • 博客积分: 10016
  • 博客等级: 上将
  • 技术积分: 8588
  • 用 户 组: 普通用户
  • 注册时间: 2008-05-29 19:22
文章分类

全部博文(668)

文章存档

2011年(1)

2010年(2)

2009年(273)

2008年(392)

分类:

2009-05-13 11:43:28

1)登上算法 
用登山算法求解背包问题 function []=DengShan(n,G,P,W) %n是背包的个数,G是背包的总容量,P是价值向量,W是物体的重量向量 %n=3;G=20;P=[25,24,15];W2=[18,15,10];%输入量 W2=W; [Y,I]=sort(-P./W2);W1=[];X=[];X1=[]; for i=1:length(I) W1(i)=W2(I(i)); end W=W1; for i=1:n X(i)=0; RES=G;%背包的剩余容量 j=1; while W(j)<=RES X(j)=1; RES=RES-W(j); j=j+1; end X(j)=RES/W(j); end for i=1:length(I) X1(I(i))=X(i); end X=X1; disp('装包的方法是');disp(X);disp(X.*W2);disp('总的价值是:');disp(P*X'); 

时间复杂度是非指数的 

2)递归法 
先看完全背包问题 
一个旅行者有一个最多能用m公斤的背包,现在有n种物品,每件的重量分别是W1,W2,...,Wn, 
每件的价值分别为C1,C2,...,Cn.若的每种物品的件数足够多. 
求旅行者能获得的最大总价值。 
本问题的数学模型如下: 
设 f(x)表示重量不超过x公斤的最大价值, 
则 f(x)=max{f(x-i)+c[i]} 当x>=w[i] 1<=i<=n 
可使用递归法解决问题程序如下: 
program knapsack04; 
const maxm=200;maxn=30; 
type ar=array[0..maxn] of integer; 
var m,n,j,i,t:integer; 
c,w:ar; 
function f(x:integer):integer; 
var i,t,m:integer; 
begin 
if x=0 then f:=0 else 
begin 
t:=-1; 
for i:=1 to n do 
begin 
if x>=w[i] then m:=f(x-i)+c[i]; 
if m>t then t:=m; 
end; 
f:=t; 
end; 
end; 
begin 
readln(m,n); 
for i:= 1 to n do 
readln(w[i],c[i]); 
writeln(f(m)); 
end. 
说明:当m不大时,编程很简单,但当m较大时,容易超时. 
4.2 改进的递归法 
改进的的递归法的思想还是以空间换时间,这只要将递归函数计算过程中的各个子函数的值保存起来,开辟一个 
一维数组即可 
程序如下: 
program knapsack04; 
const maxm=2000;maxn=30; 
type ar=array[0..maxn] of integer; 
var m,n,j,i,t:integer; 
c,w:ar; 
p:array[0..maxm] of integer; 
function f(x:integer):integer; 
var i,t,m:integer; 
begin 
if p[x]<>-1 then f:=p[x] 
else 
begin 
if x=0 then p[x]:=0 else 
begin 
t:=-1; 
for i:=1 to n do 
begin 
if x>=w[i] then m:=f(i-w[i])+c[i]; 
if m>t then t:=m; 
end; 
p[x]:=t; 
end; 
f:=p[x]; 
end; 
end; 
begin 
readln(m,n); 
for i:= 1 to n do 
readln(w[i],c[i]); 
fillchar(p,sizeof(p),-1); 
writeln(f(m)); 
end. 
3)贪婪算法 
改进的背包问题:给定一个超递增序列和一个背包的容量,然后在超递增序列中选(只能选一次)或不选每一个数值,使得选中的数值的和正好等于背包的容量。 

代码思路:从最大的元素开始遍历超递增序列中的每个元素,若背包还有大于或等于当前元素值的空间,则放入,然后继续判断下一个元素;若背包剩余空间小于当前元素值,则判断下一个元素 
简单模拟如下: 

#define K 10 
#define N 10 

#i nclude  
#i nclude  

void create(long array[],int n,int k) 
{/*产生超递增序列*/ 
int i,j; 
array[0]=1; 
for(i=1;i
long t=0; 
for(j=0;jt=t+array[j]; 
array[i]=t+random(k)+1; 


void output(long array[],int n) 
{/*输出当前的超递增序列*/ 
int i; 
for(i=0;i
if(i%5==0) 
printf("\n"); 
printf("%14ld",array[i]); 



void beibao(long array[],int cankao[],long value,int count) 
{/*背包问题求解*/ 
int i; 
long r=value; 
for(i=count-1;i>=0;i--)/*遍历超递增序列中的每个元素*/ 

if(r>=array[i])/*如果当前元素还可以放入背包,即背包剩余空间还大于当前元素*/ 

r=r-array[i]; 
cankao[i]=1; 

else/*背包剩余空间小于当前元素值*/ 
cankao[i]=0; 



void main() 

long array[N]; 
int cankao[N]={0}; 
int i; 
long value,value1=0; 
clrscr(); 
create(array,N,K); 
output(array,N); 
printf("\nInput the value of beibao:\n"); 
scanf("%ld",&value); 
beibao(array,cankao,value,N); 
for(i=0;iif(cankao[i]==1) 
value1+=array[i]; 
if(value==value1) 

printf("\nWe have got a solution,that is:\n"); 
for(i=0;iif(cankao[i]==1) 

if(i%5==0) 
printf("\n"); 
printf("%13ld",array[i]); 


else 
printf("\nSorry.We have not got a solution.\n"); 

贪婪算法的另一种写法,beibao函数是以前的代码,用来比较两种算法: 

#define K 10 
#define N 10 

#i nclude  
#i nclude  

void create(long array[],int n,int k) 

int i,j; 
array[0]=1; 
for(i=1;i
long t=0; 
for(j=0;jt=t+array[j]; 
array[i]=t+random(k)+1; 


void output(long array[],int n) 

int i; 
for(i=0;i
if(i%5==0) 
printf("\n"); 
printf("%14ld",array[i]); 



void beibao(long array[],int cankao[],long value,int count) 

int i; 
long r=value; 
for(i=count-1;i>=0;i--) 

if(r>=array[i]) 

r=r-array[i]; 
cankao[i]=1; 

else 
cankao[i]=0; 



int beibao1(long array[],int cankao[],long value,int n) 
{/*贪婪算法*/ 
int i; 
long value1=0; 
for(i=n-1;i>=0;i--)/*先放大的物体,再考虑小的物体*/ 
if((value1+array[i])<=value)/*如果当前物体可以放入*/ 

cankao[i]=1;/*1表示放入*/ 
value1+=array[i];/*背包剩余容量减少*/ 

else 
cankao[i]=0; 
if(value1==value) 
return 1; 
return 0; 


void main() 

long array[N]; 
int cankao[N]={0}; 
int cankao1[N]={0}; 
int i; 
long value,value1=0; 
clrscr(); 
create(array,N,K); 
output(array,N); 
printf("\nInput the value of beibao:\n"); 
scanf("%ld",&value); 
beibao(array,cankao,value,N); 
for(i=0;iif(cankao[i]==1) 
value1+=array[i]; 
if(value==value1) 

printf("\nWe have got a solution,that is:\n"); 
for(i=0;iif(cankao[i]==1) 

if(i%5==0) 
printf("\n"); 
printf("%13ld",array[i]); 


else 
printf("\nSorry.We have not got a solution.\n"); 
printf("\nSecond method:\n"); 
if(beibao1(array,cankao1,value,N)==1) 

for(i=0;iif(cankao1[i]==1) 

if(i%5==0) 
printf("\n"); 
printf("%13ld",array[i]); 


else 
printf("\nSorry.We have not got a solution.\n"); 


4)动态规划算法 

解决0/1背包问题的方法有多种,最常用的有贪婪法和动态规划法。其中贪婪法无法得到问题的最优解,而动态规划法都可以得到最优解,下面是用动态规划法来解决0/1背包问题。 

动态规划算法与分治法类似,其基本思想是将待求解问题分解成若干个子问题,然后从这些子问题的解得到原问题的解。与分治法不同的是,适合于用动态规划法求解的问题,经分解得到的子问题往往不是互相独立的,若用分治法解这类问题,则分解得到的子问题数目太多,以至于最后解决原问题需要耗费过多的时间。动态规划法又和贪婪算法有些一样,在动态规划中,可将一个问题的解决方案视为一系列决策的结果。不同的是,在贪婪算法中,每采用一次贪婪准则便做出一个不可撤回的决策,而在动态规划中,还要考察每个最优决策序列中是否包含一个最优子序列。 


0/1背包问题 


在0 / 1背包问题中,需对容量为c 的背包进行装载。从n 个物品中选取装入背包的物品,每件物品i 的重量为wi ,价值为pi 。对于可行的背包装载,背包中物品的总重量不能超过背包的容量,最佳装载是指所装入的物品价值最高,即p1*x1+p2*x1+...+pi*xi(其1<=i<=n,x取0或1,取1表示选取物品i) 取得最大值。 
在该问题中需要决定x1 .. xn的值。假设按i = 1,2,...,n 的次序来确定xi 的值。如果置x1 = 0,则问题转变为相对于其余物品(即物品2,3,.,n),背包容量仍为c 的背包问题。若置x1 = 1,问题就变为关于最大背包容量为c-w1 的问题。现设r?{c,c-w1 } 为剩余的背包容量。 
在第一次决策之后,剩下的问题便是考虑背包容量为r 时的决策。不管x1 是0或是1,[x2 ,.,xn ] 必须是第一次决策之后的一个最优方案,如果不是,则会有一个更好的方案[y2,.,yn ],因而[x1,y2,.,yn ]是一个更好的方案。 
假设n=3, w=[100,14,10], p=[20,18,15], c= 116。若设x1 = 1,则在本次决策之后,可用的背包容量为r= 116-100=16 。[x2,x3 ]=[0,1] 符合容量限制的条件,所得值为1 5,但因为[x2,x3 ]= [1,0] 同样符合容量条件且所得值为1 8,因此[x2,x3 ] = [ 0,1] 并非最优策略。即x= [ 1,0,1] 可改进为x= [ 1,1,0 ]。若设x1 = 0,则对于剩下的两种物品而言,容量限制条件为116。总之,如果子问题的结果[x2,x3 ]不是剩余情况下的一个最优解,则[x1,x2,x3 ]也不会是总体的最优解。在此问题中,最优决策序列由最优决策子序列组成。假设f (i,y) 表示剩余容量为y,剩余物品为i,i + 1,...,n 时的最优解的值,即:利用最优序列由最优子序列构成的结论,可得到f 的递归式为: 
当j>=wi时: f(i,j)=max{f(i+1,j),f(i+1,j-wi)+vi} ①式 
当0<=jfn( 1 ,c) 是初始时背包问题的最优解。 
以本题为例:若0≤y<1 0,则f ( 3 ,y) = 0;若y≥1 0,f ( 3 ,y) = 1 5。利用②式,可得f (2, y) = 0 ( 0≤y<10 );f(2,y)= 1 5(1 0≤y<1 4);f(2,y)= 1 8(1 4≤y<2 4)和f(2,y)= 3 3(y≥2 4)。因此最优解f ( 1 , 11 6 ) = m a x {f(2,11 6),f(2,11 6 - w1)+ p1} = m a x {f(2,11 6),f(2,1 6)+ 2 0 } = m a x { 3 3,3 8 } = 3 8。 
现在计算xi 值,步骤如下:若f ( 1 ,c) =f ( 2 ,c),则x1 = 0,否则x1 = 1。接下来需从剩余容量c-w1中寻求最优解,用f (2, c-w1) 表示最优解。依此类推,可得到所有的xi (i= 1.n) 值。 
在该例中,可得出f ( 2 , 116 ) = 3 3≠f ( 1 , 11 6 ),所以x1 = 1。接着利用返回值3 8 -p1=18 计算x2 及x3,此时r = 11 6 -w1 = 1 6,又由f ( 2 , 1 6 ) = 1 8,得f ( 3 , 1 6 ) = 1 4≠f ( 2 , 1 6 ),因此x2 = 1,此时r= 1 6 -w2 = 2,所以f (3,2) =0,即得x3 = 0。
阅读(1062) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~