背包问题之彻底背包

问题描述
有N中物品和一个容量为V的背包,每种物品都有无限件能够使用。第i中物品的费用是c[i],价值是w[i]。
求将哪些物品放入背包能够使这些物品的费用总和不超过背包容量且价值总和最大。

分析思路
每一个物品都是无限件,也就当取第i件物品的时候,有0件、1件、2件。。。。等等多种状况。
令f[i,v]表示前i种物品放入一个容量为v的背包时候 取得的最大价值。动态转移方程为:
           dp[i,v]=max{   dp[i-1][v-k*c[i]]+w[i]   ||  0<=k*c[i] <=v}

# include <stdio.h >
# include <string.h >
int main()
{
    int N,M,c[ 100],w[ 100],dp[ 200][ 200],dp1[ 2000];
    while (scanf( "%d%d", &M, &N) !=EOF)
    {
       //获取数据
        for( int i = 1;i < =N;i ++)
            scanf( "%d%d", &c[i], &w[i]);

    //数据初始化
        for( int j = 0;j < =M;j ++)
            if(j > =c[ 1]) dp[ 1][j] =w[ 1];
            else        dp[ 1][j] = 0;

    //利用递推公式
            for( int i = 2;i < =N;i ++)
                for( int j = 0;j < =M;j ++)
                {

                  dp[i][j] =dp[i - 1][j];

                    int max_temp = 0;
                    for( int k = 0;k < =j /c[i];k ++)   //这里K从1开始也能够的。由于K=0的状况也被归入了dp[i][j]=dp[i-1][j]
                        max_temp =(dp[i - 1][j -k *c[i]] +k *w[i]) >max_temp ?(dp[i - 1][j -k *c[i]] +k *w[i]) :max_temp;
                    dp[i][j] =max_temp;
                }
               
      printf( "%d\n",dp[N][M]);
    }
    return 0;
}


一样的,这个能够进行改进。使用一维数组的方式。
for i = 1....N
      for v = 0.....V
           dp[v] =max{ dp[v] , dp[v -c[i]] +w[i]  }
一样的当v<c[i]的时候dp[v]仍是原来的没有改变,
这个代码在改进一下就是
for i = 1.....N
      for v =c[i]......V
            dp[v] ={ dp[v],dp[v -c[i]] +w[i] }

完整的实现
   memset(dp1, 0, sizeof(dp1));

    for( int i = 1;i < =N;i ++)
      for( int j =c[i];j < =M;j ++)
        dp1[j] =dp1[j] >dp1[j -c[i]] +w[i] ?dp1[j] :dp1[j -c[i]] +w[i];

    printf( "%d\n",dp1[M]);

这里第二层循环v的顺序和01背包是相反的。 在考虑“加选一件第i种物品”这种策略时,却正须要一个可能已选入第i种物品的子结果f[i][v-c[i]],因此就能够而且必须采用v=c[i]..V的顺序循环。
因此必定要注意01背包和彻底背包的区别。




相关文章
相关标签/搜索