您的位置:首页 > 其它

01背包

2015-08-15 09:59 281 查看

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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: