标签:lin bsp mission more nta The contains 品种 整数
Time Limit: 3000MS | Memory Limit: 30000K | |
Total Submissions:43969 | Accepted: 14873 |
Description
Input
Output
Sample Input
3 10 1 2 4 2 1 1 2 5 1 4 2 1 0 0
Sample Output
8 4
Source
题意:有n种硬币,每一枚有一个价值和个数。现在取出一些硬币,面值相加得到结果S。问1~m之间可以得到多少种结果S
思路:硬币为物品,面值为体积,m为背包总容积。一次考虑每种硬币是否被用于拼成最终的面值,以“已经考虑过的物品种数”i作为DP的阶段。阶段i时,dp[j]表示前i种硬币能否拼成面值j。
但是这道题只关注“可行性”而不是“最优性”,可以发现前i种硬币能够拼成面值j只有两种可能。1、前i-1种就可以拼成面值j 2、使用了第i种硬币,发现dp[j-ai]为true,从而dp[j]变为true
于是就有一种贪心策略:设used[j]表示dp[j]在阶段i时为true至少要用到多少枚第i种硬币,并尽量选择第一种情况。在dp[j-ai]为true时,如果dp[j]已经为true,则不执行dp转移,并令used[j]=0。否则执行dp[j] = dp[j] or dp[j - ai]的转移,并令used[j] = used[j - ai] + 1
多重背包问题可以将物品拆分变成01背包问题。拆分方法有直接拆分法,二进制拆分法和单调队列。
二进制拆分法是把数量为Ci的第i种物品拆分成p+2个物品,p是满足2^0 + 2^1 + 2^2 + ... + 2^p <= Ci的最大的整数。
他们的体积分别为2^0*Vi, 2^1*Vi, ..., 2^p*Vi, Ri * Vi, 其中Ri= Ci - 2^0 - 2^1 - 2^2 - ... - 2^p
1 //#include <bits/stdc++.h> 2 #include<iostream> 3 #include<cmath> 4 #include<algorithm> 5 #include<stdio.h> 6 #include<cstring> 7 #include<map> 8 9 #define inf 0x3f3f3f3f 10 using namespace std; 11 typedef long long LL; 12 13 int n, m; 14 const int maxn = 105; 15 const int maxm = 1e5 + 5; 16 int a[maxn], c[maxn]; 17 int used[maxm]; 18 bool dp[maxm]; 19 20 int main() 21 { 22 while(scanf("%d%d", &n, &m) != EOF && (n || m)){ 23 for(int i = 1; i <= n; i++){ 24 scanf("%d", &a[i]); 25 } 26 for(int i = 1; i <= n; i++){ 27 scanf("%d", &c[i]); 28 } 29 30 memset(dp, 0, sizeof(dp)); 31 dp[0] = true; 32 for(int i = 1; i <= n; i++){ 33 memset(used, 0, sizeof(used)); 34 for(int j = a[i]; j <= m; j++){ 35 if(!dp[j] && dp[j - a[i]] && used[j - a[i]] < c[i]){ 36 dp[j] = true; 37 used[j] = used[j - a[i]] + 1; 38 } 39 } 40 } 41 42 int ans = 0; 43 for(int i = 1; i <= m; i++){ 44 if(dp[i])ans++; 45 } 46 printf("%d\n", ans); 47 } 48 return 0; 49 }
标签:lin bsp mission more nta The contains 品种 整数
原文地址:https://www.cnblogs.com/wyboooo/p/9757029.html