题目类型 DP
题目意思
给出 n (1 <= n <= 100) 种硬币和一个数 m (m <= 100000) 其中每种硬币给出面值(1-100000) 和 数量(1-1000)
问这些硬币能拼凑出多少种小于等于 m 的数
解题方法
用二进制优化的多重背包也可以过不过要对某些数据进行优化 例如当硬币数量为1时直接用01背包的方法 当 m/面值 <= 数量时直接用完全背包的方法
或者参考背包九讲的方法
用单调队列优化也可以 -> 单调队列优化题解
参考代码 - 有疑问的地方在下方留言 看到会尽快回复的
#include <iostream> #include <cstdio> #include <cstring> using namespace std; bool dp[100010]; int a[110], b[110]; int main() { int n, V; while(scanf("%d%d", &n, &V), n || V) { for( int i=0; i<n; i++ ) scanf("%d", &a[i]); for( int i=0; i<n; i++ ) scanf("%d", &b[i]); memset(dp, 0, sizeof(dp)); dp[0] = true; for( int i=0; i<n; i++ ) { if(b[i] == 1) { for( int j=V; j>=a[i]; j-- ) if(dp[j-a[i]]) dp[j] = true; continue; } if(V/a[i] <= b[i]) { for( int j=0; j<=V-a[i]; j++ ) if(dp[j]) dp[j+a[i]] = true; continue; } int k = 1; while(k <= b[i]) { for( int j=V; j>=a[i]*k; j-- ) { if(dp[j-a[i]*k]) dp[j] = true; } b[i] -= k; k *= 2; } if(b[i]) { for( int j=V; j>=b[i]*a[i]; j-- ) { if(dp[j-b[i]*a[i]]) dp[j] = true; } } } int ans = 0; for( int i=1; i<=V; i++ ) if(dp[i]) ans++; printf("%d\n", ans); } return 0; }