题目链接:http://noi.openjudge.cn/ch0206/2985/
n=5,5个数分别为1,2,3,4,5,t=5;
那么可能的组合有5=1+4和5=2+3和5=5三种组合方式。
接下来的一行是n个正整数,用空格隔开。
01背包的数量问题和普通01背包问题的不同在于,普通01背包所求的是最大价值的问题,而不考虑是否正好能够购买这些物品。也就是说,购买物品的花费不一定就是背包容量的总和。
01背包的数量问题,就是利用正好能够容纳这个价值的元素进行状态转移,它的转移 = 不考虑当前数的转移 + 考虑当前数的转移。这个数量是正好的。
转换为一维背包,应该从大到小考虑所有“正好容纳”的状态。
二维的初始值的设置需要思想的是,根据数的大小来设置。例如 一个价值5,那么f[i][5] = 1。保证只考虑这个物品的正好数为1种方法。
而一维的初始值设置f[0]为1,因为这里的f[0]对应的是 f[j-v]的正好转移。
code:
#include<bits/stdc++.h> using namespace std; #pragma GCC optimize(2) #define ll long long inline int read() { int x=0,f=1;char ch=getchar(); while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();} while (ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();} return x*f; } const int nn = 1010; int a[25]; int f[25][nn]; int ff[nn]; int main() { ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0); int n,t,v; cin>>n>>t; /* 二维方法 for(int i=1;i<=n;i++) { cin>>a[i]; f[i][a[i]] = 1;//初始为 物品对应和为1,保证一定有一次和时等于这个数 } //f[i][j] 表示 前i个数字,总和j的组合的方式的数量 for(int i=1;i<=n;i++) for(int j=1;j<=t;j++) { if(j>=a[i]) f[i][j]+=f[i-1][j]+f[i-1][j-a[i]]; else f[i][j]+=f[i-1][j]; } */ ff[0]=1; for(int i=1;i<=n;i++) { cin>>v; for(int j=t;j>=v;j--) ff[j]+=ff[j-v]; } cout<<ff[t]<<endl; }