题意:现有n种面额的硬币,面额、个数分别为A_i、C_i,要求最多能给出几种不超过m的金额。
分析:这是一个多重部分和问题(多重背包问题),最基本的做法是:
dp[i][j] := 前i种硬币能否凑成j
递推关系式:
dp[i][j]=1 (存在k,使dp[i-1][j-k*a[i]]=1,其中k<=c[i]、k*a[i]<=j)
#include<iostream>
using namespace std;
int dp[105][100005];
int a[105];
int c[105];
int main() {
int n, m;
cin >> n >> m;
memset(dp, 0, sizeof(dp));
for (int i = 0; i < n; ++i) {
cin >> a[i];
}
for (int i = 0; i < n; ++i) {
cin >> c[i];
}
dp[0][0] = 1;
for (int i = 0; i < n; ++i) {
for (int j = 0; j <= m; ++j) {
for (int k = 0; k <= c[i] && k*a[i] <= j; ++k) {
dp[i + 1][j] |= dp[i][j - k*a[i]];
}
}
}
int count = 0;
for (int i = 1; i <= m; ++i) {
if (dp[n][i]) {
count++;
}
}
cout << count << endl;
return 0;
}
dp[i][j] := 用前i种硬币凑成j时,第i种硬币最多剩余数(-1表示配不出来)
- 如果dp[i - 1][j] >= 0(前i-1个数可以凑出j,那么第i个数根本用不着)则dp[i][j]=C[i],
- 如果j < a[i]或者dp[i][j - a[i]] <=0 (面额太大或者在配更小的数的时候就用光了)dp[i][j] = -1,
- 其他(将第i个数用掉一个)dp[i][j] = dp[i][j-a[i]] - 1
#include<iostream>
using namespace std;
int dp[105][100005];
int a[105];
int c[105];
int main() {
int n, m;
while ((cin >> n >> m) && n + m) {
memset(dp, -1, sizeof(dp));
for (int i = 0; i < n; ++i) {
cin >> a[i];
}
for (int i = 0; i < n; ++i) {
cin >> c[i];
}
dp[0][0] = 0;
for (int i = 0; i < n; ++i) {
for (int j = 0; j <= m; ++j) {
if (dp[i][j] >= 0) {
dp[i + 1][j] = c[i];
}
else if (j < a[i] || dp[i + 1][j - a[i]] <= 0) {
dp[i + 1][j] = -1;
}
else {
dp[i + 1][j] = dp[i + 1][j - a[i]] - 1;
}
}
}
int count = 0;
for (int i = 1; i <= m; ++i) {
if (dp[n][i] != -1) {
count++;
}
}
cout << count << endl;
}
return 0;
}
利用一维dp数组:
#include<iostream>
using namespace std;
int dp[100005];
int a[105];
int c[105];
int main() {
int n, m;
while ((cin >> n >> m) && n + m) {
memset(dp, -1, sizeof(dp));
for (int i = 0; i < n; ++i) {
cin >> a[i];
}
for (int i = 0; i < n; ++i) {
cin >> c[i];
}
dp[0] = 0;
for (int i = 0; i < n; ++i) {
for (int j = 0; j <= m; ++j) {
if (dp[j] >= 0) {
dp[j] = c[i];
}
else if (j < a[i] || dp[j - a[i]] <= 0) {
dp[j] = -1;
}
else {
dp[j] = dp[j - a[i]] - 1;
}
}
}
int count = 0;
for (int i = 1; i <= m; ++i) {
if (dp[i] != -1) {
count++;
}
}
cout << count << endl;
}
return 0;
}