题意:有n种硬币,价值为Ai,每种Ci个。求在m以内能组成多少种金额。
这是一个多重背包问题,主要问题在于每种Ci个,很容易TLE。
因为比较简单,需要注意的要点就写在注释里了。
#include <iostream>
#include <vector>
#include <algorithm>
#include "string.h"
using namespace std;
typedef long long ll;
const int MOD = 1e9 + 9;
#define mem(x,i) memset(x,i,sizeof x)
bool dp[100010];
int sum[100010];
struct node{
int c;
int v;
}num[1001];
int main() {
// freopen("in.txt","r",stdin);
// freopen("out.txt","w",stdout);
int n, m;
while (cin >> n >> m && (n || m)) {
mem(dp,0);
for (int i = 1; i <= n; ++i) {
scanf("%d",&num[i].v);
}
for (int i = 1; i <= n; ++i) {
scanf("%d",&num[i].c);
}
dp[0] = true;
int ans = 0;
for (int i = 1; i <= n; ++i) {
mem(sum,0);
for (int j = num[i].v; j <= m; ++j) {
if (!dp[j]&& dp[j-num[i].v] && sum[j-num[i].v] < num[i].c) //这个sum数组是代码
//的核心,记录在第i件物品的循环中,出现了几次。这里解释一下,因为当我们找到了第一个
//符合情况的数,比如dp[1]=1,dp[3]=0,恰好我们在循环的物品价值为2,我们可以
//记录dp[3]=1,dp[5]=1依次类推,因为只有这种物品的价值是2,所以肯定是连续的
//而sum正是是借助了这个原理,能够简单地统计这个物品到底出现了几次。
{
sum[j] = sum[j-num[i].v]+1;
ans++;
dp[j] = true;
}
}
}
printf("%d\n",ans);
}
}