hdu2844 多重背包+二进制优化(多重背包的完全背包优化解法)
2016-10-12 18:40
405 查看
Coins
[b] Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 12746 Accepted Submission(s): 5116
[/b]
[align=left]Problem Description[/align]
Whuacmers use coins.They have coins of value A1,A2,A3...An Silverland dollar. One day Hibix opened purse and found there were some coins. He decided to buy a very nice watch in a nearby shop. He wanted
to pay the exact price(without change) and he known the price would not more than m.But he didn't know the exact price of the watch.
You are to write a program which reads n,m,A1,A2,A3...An and C1,C2,C3...Cn corresponding to the number of Tony's coins of value A1,A2,A3...An then calculate how many prices(form 1 to m) Tony can pay use these coins.
[align=left]Input[/align]
The input contains several test cases. The first line of each test case contains two integers n(1 ≤ n ≤ 100),m(m ≤ 100000).The second line contains 2n integers, denoting A1,A2,A3...An,C1,C2,C3...Cn (1
≤ Ai ≤ 100000,1 ≤ Ci ≤ 1000). The last test case is followed by two zeros.
[align=left]Output[/align]
For each test case output the answer on a single line.
[align=left]Sample Input[/align]
3 10
1 2 4 2 1 1
2 5
1 4 2 1
0 0
[align=left]Sample Output[/align]
8
4
题意:给你n种钱,每种钱有Cn张,问你最多能组成多少种钱数。
思路:好开心的一道题,昨晚就在想多重背包的二进制优化这个问题,结果今天就做到了。o(^▽^)o。这个本来是一个非常简单的多重背包问题,看一下if (dp[ i - money[j] ] == 1) dp[i] = 1;但是他给的数据太大了,1e5的钱,有100种钱,每种钱1000张,这样的话复杂度就变成了1e10,显然会TLE,所以我们用二进制对钱的数量进行优化,那1000张,可以化为2*log2(1000),不到20,这样的话,复杂度就到了1e8,勉强能过。。。不过我在做出来以后看他们的题解,发现有的人用了另一种方法,他把这个题当作完全背包设了一个use[i]的数组,代表
i 元用了多少张这种钱,每放一种钱,他就memset一遍,这样的话,他的复杂度只有1e7。这很ACM。
贴一下二进制优化多重背包的代码:
#include<iostream> #include<algorithm> #include<cstdio> #include<cstring> using namespace std; int a[105][15]; int dp[100050]; int value[105]; void bt(int re, int n){ int number = 0; int k = 1; while(n >= k){ number++; n -= k; a[re][number] = k; k = k << 1; } while(n > 0){ number++; while(k > n) k = k >> 1; n -= k; a[re][number] = k; } a[re][0] = number; } int main(){ int n,m,temp; while(scanf("%d%d",&n,&m) && n+m){ memset(dp,0,sizeof(dp)); for(int i = 0; i < n; i++) scanf("%d",&value[i]); for(int i = 0; i < n; i++){ scanf("%d",&temp); bt(i,temp); } dp[0] = 1; for(int i = 0; i < n; i++) for(int j = 1; j <= a[i][0]; j++) for(int k = m; k >= a[i][j]*value[i]; k--) if(dp[k-a[i][j]*value[i]] == 1)dp[k] = 1; int number = 0; for(int i = 1; i <= m; i++) if(dp[i])number++; cout << number <<endl; } }
完全背包加use数组的解法:
#include <stdio.h> #include <string.h> bool dp[100010]; int use[100010];//i元钱时某种钱用的次数 int n,m; int val[110],num[110]; void solve() { memset(dp,0,sizeof(dp)); dp[0] = 1; int count = 0; for(int i = 1; i <= n; i++) { memset(use,0,sizeof(use)); //每次初始化第i种钱用了0次 for(int j = val[i]; j <= m; j++)//顺序枚举钱数 { if(dp[j-val[i]] && !dp[j] && use[j-val[i]] < num[i]) { dp[j] = 1; use[j] = use[ j-val[i] ]+1;//到达j元用的i种钱的次数是到达 j-val[i]元用的次数加1 count++; } } } printf(%d ,count); } int main() { while(~scanf(%d %d,&n,&m)) { if(n == 0 && m == 0) break; for(int i = 1; i <= n; i++) scanf(%d,&val[i]); for(int i = 1; i <= n; i++) scanf(%d,&num[i]); solve(); } return 0; } </string.h></stdio.h>
感谢这个博主,贴一下他的这篇博客网址:
点击打开链接
相关文章推荐
- 完全背包的二进制优化
- HDU2844_Coins【多重背包】【二进制优化】
- hdu2844 Coins(普通的多重背包 + 二进制优化)
- Piggy-Bank (HDU_1114) 完全背包+二进制优化
- HDU2844_Coins【多重背包】【二进制优化】
- hdu 1059 多重背包 二进制优化 (完全 , 01)背包结婚
- HDU2844【背包问题(二进制优化)】
- 动态规划:HDU2844-Coins(多重背包的二进制优化)
- 关于完全背包问题用二进制优化的可行性证明
- 背包模板(01,完全,多重背包的二进制优化和单调队列优化
- DP(完全背包二进制优化) Problem T:Dividing(HDU 1059)
- hdu2844 Coins(多重背包+二进制优化)
- FATE (HDU_2159) 二维完全背包 + 二进制优化
- 完全背包问题(二进制解法)
- 多重背包(二进制优化)
- hdu 1171 二进制优化的多重背包
- hdu1171--C - Big Event in HDU(多重背包+二进制优化)
- (POJ1376)Cash Machine <多重背包问题变形,二进制优化>
- 暑期dp46道(12)--HDOJ 2191 多重背包+二进制优化
- HDU Dividing (多重背包+二进制优化)