EH's Blog

题目情境#

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

题目描述

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

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

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

输出 最优选法的方案数。注意答案可能很大,请输出答案模 109+710^9+7 的结果。

输入格式

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

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

输出格式

输出一个整数,表示 方案数 模 109+710^9+7 的结果。

输入 #1

4 5
1 2
2 4
3 4
4 6
plaintext

输出 #1

2
plaintext

算法解析:#

背包方案数:f[j]f[j] 存容量 jj 的最优价值,c[j]c[j] 存达到该最优价值的方案数。01 背包转移时:若 f[j−v]+w>f[j]f[j-v]+w > f[j],方案数 c[j]=c[j−v]c[j]=c[j-v](继承);若相等,c[j]+=c[j−v]c[j]+=c[j-v]。最后答案 c[m]c[m](取模)。

C++代码实现#

// 不超背包容量的方案数
#include<iostream>
#include<cstring>
using namespace std;

const int N=1010, mod=1e9+7;
int f[N],c[N];
// f[i]表示背包容量为i时最优选法的总价值
// c[i]表示背包容量为i时最优选法的方案数

int main(){
  int n, m, v, w;   
  scanf("%d%d", &n, &m);    
  for(int i=0;i<=m;i++) c[i]=1;    
  
  for(int i=1; i<=n; i++){    //枚举物品
    scanf("%d%d",&v,&w);
    for(int j=m; j>=v; j--){  //枚举体积
      if(f[j-v]+w>f[j]){      //装新物品总价值更大
        f[j]=f[j-v]+w;
        c[j]=c[j-v];
      }
      else if(f[j-v]+w==f[j]) //装新物品总价值相等
        c[j]=(c[j]+c[j-v])%mod;     
    }
  }
  printf("%d\n",c[m]);
}
c
E13 背包方案数
https://ehnotgod.site/blog/e13-%E8%83%8C%E5%8C%85%E6%96%B9%E6%A1%88%E6%95%B0
Author EH
Published at August 8, 2026