• 动态规划 0--1 背包问题


    给定一个物品集合s={1,2,3,…,n},物品i的重量是wi,其价值是vi,背包的容量为W,即最大载重量不超过W。在限定的总重量W内,我们如何选择物品,才能使得物品的总价值最大。
    如果物品不能被分割,即物品i要么整个地选取,要么不选取;
    不能将物品i装入背包多次,也不能只装入部分物品i,则该问题称为0—1背包问题。

    如果物品可以拆分,则问题称为背包问题,适合使用贪心算法

    给定n种物品和一背包。物品i的重量是wi,其价值为vi,背包的容量为C。问:应如何选择装入背包的物品,使得装入背包中物品的总价值最大?

         设(y1,y2,…,yn)是 (3.4.1)的一个最优解.则(y2,…,yn)是下面相应子问题的一个最优解:

         证明:使用反证法。若不然,设(z2,z3,…,zn)是上述子问题的一个最优解,而(y2,y3,…,yn)不是它的最优解。显然有                                     ∑vizi > ∑viyi   (i=2,…,n)      且                           w1y1+ ∑wizi<= c      因此                       v1y1+ ∑vizi (i=2,…,n) > ∑ viyi, (i=1,…,n)      说明(y1,z2, z3,…,zn)是(3.4.1)0-1背包问题的一个更优解,导出(y1,y2,…,yn)不是背包问题的最优解,矛盾。

          递推关系:

        设所给0-1背包问题的子问题

        

         的最优值为m(i,j),即m(i,j)是背包容量为j,可选择物品为i,i+1,…,n时0-1背包问题的最优值。由0-1背包问题的最优子结构性质,可以建立计算m(i,j)的递归式:

         注:(3.4.3)式此时背包容量为j,可选择物品为i。此时在对xi作出决策之后,问题处于两种状态之一:     (1)背包剩余容量是j,没产生任何效益;     (2)剩余容量j-wi,效益值增长了vi ; (3) 对于最后一个物品n , 如果 j>=Wn,则肯定装入, 获得价值Vn; 如果0<=j < Wn,则无法装入, 获得的价值为 0 。

     

     1 #include<iostream>
     2 #include<cstring>
     3 using namespace std;
     4 
     5 #define NUM 50              //物品数量的上界 
     6 #define CAP 1500            //背包容量的上界 
     7 int v[NUM];                 //物品的重量 
     8 int w[NUM];                 //物品的价值 
     9 int p[NUM][CAP];            //用于递归的数组。
    10 //形参 c 是背包的容量 W,n是物品的数量。 
    11 void knapsack(int c, int n) 
    12 { 
    13     //计算递推边界 
    14     int jMax=min(w[n]-1,c);   //分界点。 
    15     for( int j=0; j<=jMax; j++) 
    16         p[n][j]=0; 
    17     for( int j=w[n]; j<=c; j++) 
    18         p[n][j]=v[n];
    19     for( int i=n-1; i>1; i--)//计算递推式 
    20     { 
    21         jMax=min(w[i]-1,c); 
    22         for( int j=0; j<=jMax; j++) 
    23             p[i][j]=p[i+1][j]; 
    24         for(int j=w[i]; j<=c; j++) 
    25             p[i][j]=max(p[i+1][j], p[i+1][j-w[i]]+v[i]); 
    26     } 
    27     p[1][c]=p[2][c];         //计算最优值。 
    28     if (c>=w[1]) 
    29         p[1][c]=max(p[1][c], p[2][c-w[1]]+v[1]); 
    30 } 
    31 //形参数组 x 是解向量。 
    32 void traceback( int c, int n, int x[]) 
    33 { 
    34     for(int i=1; i<n; i++) 
    35     {
    36         if (p[i][c]==p[i+1][c]) x[i]=0; 
    37         else { x[i]=1; c-=w[i]; } 
    38     }
    39     x[n]= (p[n][c]) ? 1:0; 
    40 } 
    41 
    42 int main () 
    43 {
    44     int x[NUM];
    45     int W;
    46     int n;
    47     while (scanf("%d", &W) && W) 
    48     {
    49         scanf("%d", &n);
    50         for (int i=1; i<=n; i++)
    51             scanf("%d%d", &w[i], &v[i]);
    52         memset (p, 0, sizeof(p));
    53         knapsack(W, n);
    54         printf("%d
    ", p[1][W]);
    55         traceback(W, n, x);
    56         for (int i=1; i<=n; i++)
    57             if (x[i]) printf("%d ", i);
    58         printf("
    ");
    59     }
    60     return 0;
    61 }
    View Code

     

     

  • 相关阅读:
    常用内建函数
    函数作用域
    异常处理语句
    迭代器---待延申扩展
    流程控制语句
    字典
    集合
    数据类型的可变与不可变
    Openstack keystone组件详解
    云计算openstack介绍(001)
  • 原文地址:https://www.cnblogs.com/acm1314/p/4578621.html
Copyright © 2020-2023  润新知