EH's Blog

题目情境#

题目链接:https://www.luogu.com.cn/problem/U224067 ↗

题目描述

有 nn 件物品和一个容量是 mm 的背包。每件物品只能使用一次。

第 ii 件物品的体积是 wiw_i,价值是 viv_i。

求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。

如果有多种方案能使得选取的物品达到最大价值,输出任何一种即可。

输入格式

第一行两个整数,nn,mm,用空格隔开,分别表示物品数量和背包容积。

接下来有 nn 行,每行两个整数 wi,viw_i,v_i,用空格隔开,分别表示第 ii 件物品的体积和价值。

输出格式

输出两行,第一行包含一个整数,表示最优解中取走了多少件物品。

第二行包含若干个用空格隔开的整数,表示最优解中所选物品的编号序列。

输入 #1

4 5
1 2
2 4
3 4
4 6
plaintext

输出 #1

2
1 4
plaintext
  • 对于 100%100\% 的数据,有 1≤n,m≤1000,0≤vi,wi≤10001 \le n,m \le 1000,0 \le v_i,w_i \le 1000.

算法解析:#

背包具体方案:用二维 f[i][j]f[i][j] 记录从第 ii 个物品开始、容量 jj 的最优价值(逆序枚举物品,便于正向回溯),同时用 p[i][j]p[i][j] 记录转移的列位置。回溯时若 p[i][j]==j−v[i]p[i][j]==j-v[i] 说明取了第 ii 个物品,输出并跳到 (i+1,j−v[i])(i+1, j-v[i]);否则跳到 (i+1,j)(i+1, j)。

C++代码实现#

#include<bits/stdc++.h>
using namespace std;

const int N=1005;
int n,m,v[N],w[N];
int f[N][N],path[N];

int main(){
  cin>>n>>m;
  for(int i=1;i<=n;i++)cin>>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,cnt=0;
  for(int i=1;i<=n;i++){
    if(j>=v[i]&&f[i][j]==f[i+1][j-v[i]]+w[i]){
      path[++cnt]=i;
      j-=v[i];
    }
  }
  cout<<cnt<<endl;
  for(int i=1;i<=cnt;i++) cout<<path[i]<<" ";
}
c
E14 背包具体方案
https://ehnotgod.site/blog/e14-%E8%83%8C%E5%8C%85%E5%85%B7%E4%BD%93%E6%96%B9%E6%A1%88
Author EH
Published at August 8, 2026