题目链接:
题意:
我有N种硬币,每种硬币有 Bi (1=<i<=N)个,每种硬币的价值为 A[i];
思路:
状态表示:f[i][j]:从前i种硬币当中选,且所选硬币的价值恰好为 j 的方案。
属性:存在性,价值为 j 的方案能否凑出来;
所以 f[i][j] 的取值就变成了 0 或者 1,分别表示不能凑出来,或者能够凑出来!
状态转移:
f [i] [j]:<— f[i-1][j] ,从前i-1种硬币当中选,且不选第i种硬币,价值为 j 的方案!
f [i][j]:<—f[i-1][j-k*a[i]],从前i种硬币当中选,并且选第i种硬币,且第i种硬币选k个,价值恰好为j的所有方案!
代码:
暴力:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const int N = 1e4 + 10;
int a[N], b[N]; //硬币的价值 !
int f[N]; //本来是2维的!
int main()
{
int n, x;
cin >> n >> x; //n种物品,背包体积为x元
for (int i=1; i <= n; i ++)
cin >> a[i] >> b[i];//输入每种物品的价值和数量
//恰好类型的初始化:
f[0] = 1; //表示从前i种硬币中选,价值为0的选法:=1表示存在,即什么都不选!
for (int i=1; i <= n; i ++) //考虑前i种物品!
{
for (int j=x; j >= 0; j --)
{
for (int k=1; k <= b[i]; k ++) //枚举每种物品选多少个合适
if (k*a[i] <= j)
f[j] = f[j] | f[j-k*a[i]];
}
}
if (f[x]) puts("Yes");
else puts("No");
return 0;
}
二进制优化:
单调队列优化: