01背包

01背包

什么是01背包?

  • 01背包就是在M件物品取出若干件放在空间为W的背包里,每件物品的体积为C1,C2,…,Cn,与之相对应的价值为W1,W2,…,Wn。求将哪些物品装入背包可使总价值最大。

01背包的分析:

  • 子问题:F[i][j]表示前 i 件物品中选取若干件物品放入剩余空间为 j 的背包中所能得到的最大价值。
  • 判断第 i 件物品放还是不放:
    • F [ i ][ j ] = max {  F [ i-1 ][ j ] ,F[ i-1 ][ j-C[ i ] ] + w[ i ]  }。
    • F [ i-1 ][ j ] 表示前i-1件物品中选取若干件物品放入剩余空间为j的背包中所能得到的最大价值。
    • F[ i-1 ][ j-C[ i ] ] + w[ i ] 表示前i-1件物品中选取若干件物品放入剩余空间为j-C[i]的背包中所能取得的最大价值加上第i件物品的价值。

模板代码:

  • 二维数组:
  • #include <iostream>
    #include <string.h>
    #include <stdio.h>
    
    int dp[1001][1001],c[1001],w[1001];
    int main()
    {
        int t,k,v,i,j;
        scanf("%d",&t);
        while(t--)
        {
            scanf("%d %d",&k,&v);
            memset(dp,0,sizeof(dp));//初始化操作
            for(i=1;i<=k;i++)
                scanf("%d",&w[i]);
            for(i=1;i<=k;i++)
                scanf("%d",&c[i]);
            for(i=1;i<=k;i++)
            {
                for(j=0;j<=v;j++)
                {
                    if(c[i]<=j)//表示第i个物品将放入大小为j的背包中
                        dp[i][j]=dp[i-1][j]>(dp[i-1][j-c[i]]+w[i])?dp[i-1][j]:(dp[i-1][j-c[i]]+w[i]);//第i个物品放入后,那么前i-1个物品可能会放入也可能因为剩余空间不够无法放入
                    else dp[i][j]=dp[i-1][j];//第i个物品无法放入
                }
            }
            printf("%d\n",dp[k][v]);
        }
        return 0;
    }
  • 一维数组:(优化版)
  • #include <iostream>
    #include <string.h>
    #include <stdio.h>
    using namespace std;
    int dp[1001],c[1001],w[1001];
    int main()
    {
        int t,k,v,i,j;
        scanf("%d",&t);
        while(t--)
        {
            scanf("%d %d",&k,&v);
            memset(dp,0,sizeof(dp));
            for(i=1;i<=k;i++)
                scanf("%d",&w[i]);
            for(i=1;i<=k;i++)
                scanf("%d",&c[i]);
            for(i=1;i<=k;i++)
            {
                for(j=v;j>=c[i];j--)
                {
                    dp[j]=dp[j]>(dp[j-c[i]]+w[i])?dp[j]:(dp[j-c[i]]+w[i]);
                }
            }
            printf("%d\n",dp[v]);
        }
        return 0;
  • 该方法只是对背包的空间进行优化。
  • 事实上,这要求在每次主循环中我们以v=V..0的顺序推dp[v],这样才能保证推dp[v]时dp[v-c[i]]保存的是状态dp[i-1][v-c[i]]的值。
  • 所以这种解法只能由V--0,不能反过来,如果反过来就会造成物品重复放置!

练习题目:

  • hdu oj 2602 Bone Collector

你可能感兴趣的:(dp,数据结构与算法,背包)