AcWing 12. 背包问题求具体方案

AcWing 12. 背包问题求具体方案

(1)问题

在这里插入图片描述

(2)分析

我们先看一下这道题中最后要的答案是一个字典序最小的答案。因此我们从小到大遍历每个物品,如果碰到一个物品可选可不选,那么我们一定选,因为我们是从小到大遍历的,所以后遍历的物品的序号肯定大,我们就无法保证字典序最小了。

那么现在的关键是我们要保证从小到大遍历物品。

但是在作者之前的文章中写过一篇关于机器分配(分组背包与方案数)的文章。在这篇文章中我讲解过输出方案的思路。我们从小到大推导可以得到最终的答案,但是我们想要得到一个方案的话,需要倒过来遍历,即从大到小。至于为什么这样做,作者在机器分配这一题的文章中利用拓扑图做了一定的解释。

那么这道题我们也需要反过来遍历。

所以为了满足这道题从小到大解决最小字典序的问题的话,就要更改一下状态的定义。

f [ i ] [ j ] f[i][j] f[i][j]表示从i–n的物品里面选,在背包容量为j的条件下,选出最大价值。由于DP问题是按照规模从小到大计算的,所以i要从n到1枚举。这样做的好处就是,我们讨论方案的时候,将其反过来以后,就是从1到n。即从小到大。

(3)代码

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=1010;
int v[N],w[N],f[N][N],cnt[N];
int n,m;
int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++)scanf("%d%d",v+i,w+i);
    for(int i=n;i>=1;i--)
    {
        for(int j=0;j<=m;j++)
        {
            f[i][j]=f[i+1][j];
            if(j>=v[i])f[i][j]=max(f[i][j],f[i+1][j-v[i]]+w[i]);
        }
    }
    int j=m;
    int count=0;
    for(int i=1;i<=n;i++)
        if(j>=v[i]&&f[i+1][j-v[i]]+w[i]==f[i][j])
        {
            cout<<i<<" ";
            j-=v[i];
        }

    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值