导航

编程题目日志131222:01背包

Posted on 2013-12-24 18:13  生存在夹缝中  阅读(205)  评论(0)    收藏  举报

题目:

  腾妃新买了个容量为W的帅气包包,现有n件新衣服可装入其中。放入第i件衣服耗费的空间是Ci,得到的价值是Vi。求将哪些衣服装
入大包可使价值总和最大。

 

思路1:

  其实就是背包问题。这个问题的最佳方案应该是动态规划,但是我想了半天也没有想出来,只好先写出了递归的代码

方案1:

  从0到n-1遍历每一件衣服,添加在当前衣服放入或不放入背包的时候能够获得的最大值,这个最大值通过调用后面的情况得到,一直到最后一件或者背包装满为止

代码1:

 1 int MaxTotalCaculate(int *c,int *v,int current,int n,int w_left,int *board,int total)
 2 {
 3     if(current==n-1)//最后一个
 4     {
 5         if(c[current]<=w_left)
 6         {
 7             board[current]=1;
 8             total+=v[current];        
 9         }
10         return total;
11     }
12     if(w_left==0)//剩余空间0 
13         return total;
14     int condition_1=MaxTotalCaculate(c,v,current+1,n,w_left,board,total);//不装入当前点 
15     if(c[current]>w_left)//当前节点所需空间大于剩余空间 
16         return condition_1;//必须不装入 
17     total+=v[current];
18     w_left-=c[current];
19     board[current]=1;
20     int condition_2=MaxTotalCaculate(c,v,current+1,n,w_left,board,total);//装入当前节点 
21     if(condition_1>condition_2)//比较后选择最大的方案并返回 
22     {
23         board[current]=0;
24         return condition_1;
25     }
26     return condition_2;
27 }

 

思路2(依旧并非最佳算法):

  接下来继续考虑动态规划。依我现在的理解,动态规划和递归同样是找出一个大问题的重复模式,找到那个被重复的小问题解决掉。但是将递归会导致的大量重复计算通过设置中间变量的方式来替代掉,也就是说,这同样是一个用空间换时间的手段。

  由此考虑上述递归代码的重复计算部分,在于下一件衣服的放入会导致的情况被不断的重复计算。于是想到建立一个长度为n的数组,每个元素记录最后一件衣服为该元素号的时候能够获得的最大价值,由此从0遍历到n-1,这是一个n2级别的算法

 

代码:

 1 int MaxTotalBySteps(int *c,int *v,int w,int n,int *board)
 2 {
 3 //思路:存储数组value和weight,分别表示,最后一件为i时的最大价值和对应重量
 4 //从0遍历至n-1存储这两个数,每个数都可以通过前面的数计算出来
 5 //避免重复计算!!!! 
 6     int *value=malloc(sizeof(int)*n);
 7     int *weight=malloc(sizeof(int)*n);
 8     int **board_n=malloc(sizeof(int *)*n);//你妹的翔妹啊,要个总数得了呗,还得要方案
 9     int *temp=malloc(sizeof(int)*n);//计算用中间值 
10 
11     memset(value,0,sizeof(int)*n);
12     memset(weight,0,sizeof(int)*n);
13     int i;
14     for(i=0;i<=n-1;++i)
15     {
16         board_n[i]=malloc(sizeof(int)*n);
17         memset(board_n[i],0,sizeof(int)*n);
18     }
19     memset(temp,0,sizeof(int)*n);
20 //////////初始化完毕//////////////////////
21     int j,temp_max_number=0,max_number,feasible_mark=0;
22     for(i=0;i<=n-1;++i)//遍历开始
23     {
24         //对于每个遍历到的点,计算对应"最后一件为该件时的最大值"
25         for(j=0;j<=i;++j)//对于最后位为j件的情况,包含只放当前节点的可能性 
26         {
27             if(weight[j]+c[i]<=w)//如果有足够剩余空间放入i
28             {
29                 feasible_mark=1;//有了一个可行方案,否则说明该件大到根本装不下 
30                 temp[j]=value[j]+v[i];//
31             }
32         }
33         if(feasible_mark==1)//有可行方案,若没有方案则无需做任何事情 
34         {
35             temp_max_number=MaxNumberOfArray(temp,i+1);//找出最大的
36             value[i]=value[temp_max_number]+v[i];//记录当前节点为最后一件时的最大值 
37             weight[i]=weight[temp_max_number]+c[i];//记录对应重量 
38             for(j=0;j<=n-1;++j)//记录这个最大值对应方案,again,你妹的翔妹 
39                 board_n[i][j]=board_n[temp_max_number][j];
40             board_n[i][i]=1;
41             memset(temp,0,sizeof(int)*n);//清空临时数组
42             feasible_mark=0;//清空可行标志 
43         }
44     }
45     max_number=MaxNumberOfArray(value,n);//找出最终的最大值
46     for(i=0;i<=n-1;++i)
47         board[i]=board_n[max_number][i];//记录方案
48     return value[max_number];//返回最大值 
49 }

 

后续

  这两份之后我算是放弃了,于是上网去搜索真正的最佳答案,发现只差了一步啊。最佳方案应该是对于0到n-1个物品依次遍历背包重量为1到w时候的最佳方案,其复杂度为o(w*n).最佳方案介绍连接:http://blog.csdn.net/fg2006/article/details/6766384