现在的位置: 首页 > 综合 > 正文

0/1背包问题

2018年09月29日 ⁄ 综合 ⁄ 共 1597字 ⁄ 字号 评论关闭

1.动态规划是用空间换取时间的一种方法的抽象,其关键是发现子问题和记录其结果,然后利用结果减轻计算量。0/1背包问题就应用了动态规划的思想。

2.0/1背包问题:一个背包最多可以装M公斤的东西,现在有N件物品,分别为X1,X2...Xn,它们的重量分别为M1,M2...Mn,它们的价值分别为V1,V2...Vn,若某种物品只有一件,它可以放进包中,也可以不放进包中,问如何选取物品可以使得包中的物品的价值最大。

思路:目标函数为 max∑XiVi(i=1,2...n),约束条件为 ∑XiMi<=M(i=1,2...n) ,其中Xi={0,1}。可以将背包问题的求解过程看做是一系列的决策过程,即决定哪些东西放入背包,哪些不放入背包,如果一个问题的最优解包含物品n,即Xn=1,那么其余X1,X2...Xn-1构成子问题,求它们在中路 M-Mn 中的最优解。

f(N,M)=max{f(N-1,M), f(N-1,M-Mn)+Mn}


我们以最大容量M=10和物品个数N=3为例,三个物品重量分别为3,4,5,物品价值分别为4,5,6,c[i][j]保存当允许重量为j时,从前i个物品中选择可以得到的最大价值。第一行均为0,因为没有物品可以选择;第二行当j=0,1,2时c[i][j]=0,因为可以允许的重量小于任何物品的重量,当j=3时,可以将第一个物品装进去了,c[i][j]
= 4,这一行剩下的部分均为4,因为只有一个物品可以选择;第三行,当j=3时,表示可以从1,2两个物品中选择,但是总重量不可以超过3,所以c[i][j] = 4,但是当j=4时,我们可以选择有第2个物品(此时最大价值为c[i-1][j-4]+5=c[2][0]+5=5)或没有第2个物品(此时最大价值为c[i-1][j]=c[2][4]=4),所以最后的结果为5,依次类推。

我们将在总重量不超过M的前提下,前i种物品的总价格所能达到的最高值定义为A(i,
M)。
A(i, M)的递推关系为:
A(0, M) = 0
A(i, 0) = 0
如果wi > M, A(i, M) = A(i - 1, M)
如果wi ≤ M, A(i, M) = max { A(i - 1, M), Vi + A(i - 1, M - wi) }

//假设M=100,N=10,也就是10个物品、总重量最大为100
for(i=0;i<10;i++)
    for(j=0;j<100;j++)
       c[i][j]=0;/*初始化数组*/
for(i=1;i<N;i++)
    for(j=1;j<M;j++)
       {
          if(M[i]<=j) /*如果当前物品的重量小于背包重量*/
          {
                if(V[i]+c[i-1][j-V[i]]>c[i-1][j])
                    /*如果本物品的价值加上背包剩下的空间能放的物品的价值*/
                    /*大于上一次选择的最佳方案则更新c[i][j]*/
                    c[i][j]=V[i]+c[i-1][j-V[i]];
                else
                    c[i][j]=c[i-1][j];
          }
          else c[i][j]=c[i-1][j];                     
}

3.背包问题的应用

编程之美——数组分割问题:有一个没有排序、元素个数为2n的正整数数组,要求:如何能把这个数组分割为元素个数为n的两个数组,并使两个子数组的和最接近。

isOk[i][v]表示是否可以找到i个数,使得它们之和为v
初始化:isOk[0][0]=true;
isOk[i][v]=false; i>0,v>0
for(k = 1,k <= 2*n; k++){
  for(i = 1;(i <= k && i <=n);i++){
    for(v = 1;v < sum/2; v++)
      if(v >= arr[k] && isOk[i-1][v-arr[k])
        isOk[i][v] = true;
  }
}

参考资料:

http://blog.csdn.net/jhj735412/article/details/7401463

http://blog.csdn.net/yeepom/article/details/8712224

抱歉!评论已关闭.