PTA- 0-1背包问题

一、题目

给定一个承重量为C的背包,n个重量分别为w1,w2,…,wn的物品,物品i放入背包能产生pi(>0)的价值(i=1,2,…,n)。
每个物品要么整个放入背包,要么不放。要求找出最大价值的装包方案。

输入格式:
输入的第一行包含两个正整数n和C(1≤n≤20),第二行含n个正整数分别表示n个物品的重量,第三行含n个正整数分别表示n个物品放入背包能产生的价值。

输出格式:
在一行内输出结果,包括最大价值装包方案的价值、具体装包方案,用空格隔开。具体装包方案是n个物品的一个子集,用长度为n的0、1串表示(1表示对应物品被选中,0表示没有被选中)。如果这样的0、1串不唯一,取字典序最大的那个串。
在这里插入图片描述

二、代码

/*
    描述:0-1背包问题
    日期:
    思路:
        1、获取最大价值:
            dp[i][j]代表了,在前i个物品内,拿限重为j的最大价值
            (1)状态转移方程:dp[i][j]=max[ 1),2)]
                1)选i物品:dp[i][j]=value[i]+dp[i-1][j-weigh[i]]
                选了i物品,那么首先加上value[i],再者,还可以加上,前i-1个的情况下的
                限重为j-weigh[i]的物品,也即dp[i-1][j-weigh[i]]
                2)不选i物品:dp[i][j]=dp[i-1][j]
                物品的限制减一,限重不变,也即dp[i-1][j]
                3)然后在1)和2)中取最大的
                4)有个陷阱,1)中的dp[i-1][j-weigh[i]],j-weigh[i]可能会越界,所以要加一个if判断

        2、获取选择
            利用回溯法
            (1)循环n次,就是循环n个物品,循环体中询问是否dp[i][j]==dp[i-1][j]
                1)若是等于,则说明第i个物品,有它没它都一样,所以不选
                2)若是不等于,则说明第i个物品至关重要,所以要选上,并且选了之后限重会变小
                所以j-=weigh[i]
            (2)题目中要求输出字典序最大的结果,我们在求解最大价值的时候,
            也是按照前面的物品先放入背包,当且仅当后面物品放入的时候产生影响也考虑放入,
            所以我们回溯的时候得出的结果就是本题需要的答案。
*/
#include<iostream>
#include <vector>
using namespace std;

vector<int>weigh;
vector<int>value;
vector<vector<int>>dp(100,vector<int>(100,0));
string choice="000000000000000000000000000";

void dp_opt(int n,int bag_weigh)
{
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=bag_weigh;j++)
        {
            //max(选i物品,不选i物品)
            if(j>=weigh[i])
            {
                dp[i][j]=max(value[i]+dp[i-1][j-weigh[i]],dp[i-1][j]);
            }
            else dp[i][j]=dp[i-1][j];
        }
    }
    return;
}

void get_choice(int i,int j)
{
    while(i>=1)
    {
        if(dp[i][j]==dp[i-1][j]) 
        //第i个物品不重要
            choice[i]='0';
        else
        //第i个物品很重要
        {
            choice[i]='1';
            j-=weigh[i];
        }
        i--;
    }
    return;
}

int main()
{
    //输入数据物品数量、背包最大承重
    int n,bag_weigh;
    cin>>n>>bag_weigh;

    //因为dp数组的第0行和第0列是没有数据的,为0,所以这里统一
    weigh.push_back(0);
    value.push_back(0);

    //输入物品重量以及价值
    for(int i=0;i<n;i++)
    {
        int w;
        cin>>w;
        weigh.push_back(w);
    }
    for(int i=0;i<n;i++)
    {
        int v;
        cin>>v;
        value.push_back(v);
    }

    //获得最大收益
    dp_opt(n,bag_weigh);

    //获取选择
    get_choice(n,bag_weigh);

    //输出结果
    cout<<dp[n][bag_weigh]<<" ";
    for(int i=1;i<=n;i++)
        cout<<choice[i];
        
    return 0;
}
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值