题意:有n种面额的硬币。面额、个数分别为A_i、C_i,求最多能搭配出几种不超过m的金额?
思路:dp[j]就是总数为j的价值是否已经有了这种方法,如果现在没有,那么我们就一个个硬币去尝试直到有,这种价值方法有了的话,那么就是总方法数加1。多重背包可行性问题
传统多重背包三重循环会超时,因为只考虑是否可行,没有考虑剩余面额数量的因素。
o(n*v)方法
#include <iostream> #include <cstdio> #include <string.h> #include <string> #include <algorithm> using namespace std; int dp[100005]; //表示当前i价格是否出现过 int sum[100005];//当价格达到i时,最多使用这一种硬币的次数 int v[105],c[105]; int main() { int i,j,n,m; while(~scanf("%d%d",&n,&m),n+m) { for(i = 1;i<=n;i++) scanf("%d",&v[i]); for(i = 1;i<=n;i++) scanf("%d",&c[i]); memset(dp,0,sizeof(dp)); dp[0] = 1; int ans = 0; for(i=1;i<=n;i++) { memset(sum,0,sizeof(sum));//关键是用sum来限定了次数 for(j = v[i];j<=m;j++)//循环检查看是否能够出现前边没有出现的价格 { if(!dp[j] && dp[j-v[i]] && sum[j-v[i]]<c[i]) { //如果j价格没有出现过,且j-v[i]出现过,并且使用i硬币的次数没有超出给定的数量 dp[j] = 1; sum[j] = sum[j-v[i]]+1;//使用次数+1 ans++; } } } printf("%d ",ans); } return 0; }