POJ 1787 Charlie's Change

POJ 1787 Charlie‘s Change 背包系列 + 路程记录

乍一看。多重背包。

再乍。转化01背包?nonono,每样物品的数量达到了10^4,肯定会T。

再乍。看不出来了。去看大牛的题解吧。

哦——转化成完全背包。

怎么转?一般的完全背包是不限个数的。现在我们每一次枚举物品时记录一下取了多少个然后限制一下不要超过个数就好了。

恩。。

路程记录的话完全背包加一个path记录父亲。。然后多重背包加一个num数组在dp的时候直接算一算。。具体看代码。。完全背包的那版路径记录感觉十分巧妙呀嘿嘿嘿

转换方程还是老样子。。。。。。。。

f[i][j]表示用前i种硬币得到价值k时的最优解

当且仅当上一个状态可达的时候( 不为0 )才转移。

状态方程为:

f[i][j] = f[i - 1][j - val[i]] + 1; ( f[i - 1][j - val[i]] > 0 && f[i - 1][j] < f[i][j - val[i]] + 1 )

//完全背包还要加一个num[j - val[i]] + 1 <= limit[i],num为当前使用第i种的个数,limit时第i种可用的数量。

然后我们滚动数组滚一下优化一下空间

。。为什么这个做法是对的呢。。。

我们从小硬币开始遍历。。

如果是求最少的方案的话。。。

从大的硬币开始遍历就好了吧。。。【以上都是我口胡的

渣代码:

 1 #include <iostream>
 2 #include <string.h>
 3 #include <math.h>
 4 #include <algorithm>
 5 #include <stdlib.h>
 6 #include <stdio.h>
 7 #define ll long long
 8 using namespace std;
 9 const int N = 10010;
10 int f[N], n, path[N], c[5], val[5] = { 0, 1, 5, 10, 25 }, ans[N][5];
11 void zeroone(int val, int num, int pos)
12 {
13     for(int i = n; i >= val; i --){
14         if(f[i - val] && f[i - val] + num > f[i]){
15             f[i] = f[i - val] + num;
16             for(int j = 1; j <= 4; j ++){
17                 ans[i][j] = ans[i - val][j];
18             }
19             ans[i][pos] += num;
20         }
21     }
22 }
23 void complete(int val, int pos)
24 {
25     for(int i = val; i <= n; i ++){
26         if(f[i - val] && f[i - val] + 1 > f[i]){
27             f[i] = f[i - val] + 1;
28             for(int j = 1; j <= 4; j ++){
29                 ans[i][j] = ans[i - val][j];
30             }
31             ans[i][pos] += 1;
32         }
33     }
34 }
35 void multi(int num, int val, int pos)
36 {
37     if(num * val >= n){
38         complete(val, pos); return ;
39     }
40     int tmp = 1;
41     while(num >= tmp){
42         zeroone(tmp * val, tmp, pos);
43         num -= tmp;
44         tmp <<= 1;
45     }
46     if(num) zeroone(num * val, num, pos);
47 }
48 int main()
49 {
50     while(~scanf("%d%d%d%d%d", &n, &c[1], &c[2], &c[3], &c[4]) && n + c[1] + c[2] + c[3] + c[4]){
51         memset(ans, 0, sizeof(ans));
52         memset(path, 0, sizeof(path));
53         memset(f, 0, sizeof(f));
54         f[0] = 1;
55         for(int i = 1; i <= 4; i ++){
56             multi(c[i], val[i], i);
57         }
58         if(!f[n]){
59             printf("Charlie cannot buy coffee.\n"); continue;
60         }
61         printf("Throw in %d cents, %d nickels, %d dimes, and %d quarters.\n",ans[n][1],ans[n][2],ans[n][3],ans[n][4]);
62     }
63     return 0;
64 }

多重背包

 1 #include <iostream>
 2 #include <string.h>
 3 #include <math.h>
 4 #include <algorithm>
 5 #include <stdlib.h>
 6 #include <stdio.h>
 7 #define ll long long
 8 using namespace std;
 9 const int N = 10010;
10 int f[N], n, path[N], c[5], val[5] = { 0, 1, 5, 10, 25 }, ans[30], num[N];
11 int main()
12 {
13     while(~scanf("%d%d%d%d%d", &n, &c[1], &c[2], &c[3], &c[4]) && n + c[1] + c[2] + c[3] + c[4]){
14         memset(ans, 0, sizeof(ans));
15         memset(path, 0, sizeof(path));
16         memset(f, 0, sizeof(f));
17         f[0] = 1;
18         for(int i = 1; i <= 4; i ++){
19             memset(num, 0, sizeof(num));
20             for(int j = val[i]; j <= n; j ++){
21                 if(f[j - val[i]] && f[j - val[i]] + 1 > f[j] && num[j - val[i]] + 1 <= c[i]){
22                     f[j] = f[j - val[i]] + 1;
23                     num[j] = num[j - val[i]] + 1;
24                     path[j] = j - val[i];
25                 }
26             }
27         }
28         if(!f[n]){
29             printf("Charlie cannot buy coffee.\n"); continue;
30         }
31         while(n > 0){
32             ans[n - path[n]] ++;
33             n = path[n];
34         }
35         printf("Throw in %d cents, %d nickels, %d dimes, and %d quarters.\n",ans[1],ans[5],ans[10],ans[25]);
36     }
37     return 0;
38 }

完全背包

下面是两个方法最后跑出来的时间对比。上面的是完全背包,下面的是多重背包。

DONE.

------------------------------

POJ 1787 Charlie's Change

时间: 2024-10-13 10:17:56

POJ 1787 Charlie's Change的相关文章

[POJ 1787]Charlie&#39;s Change (动态规划)

题目链接:http://poj.org/problem?id=1787 题意:有4种货币分别是1元,5元,10元,20元.现在告诉你这四种货币分别有多少个,问你正好凑出P元钱最多可以用多少货币.每种货币要用多少钱. 据说此题有完全背包的写法.. 我是按照多重背包写的,速度也不是很慢. 然后记录了下前驱. 刚开始全都写挫了..虽然现在也很挫.. 凑合着看吧 -- 1 #include <cstdio> 2 #include <algorithm> 3 #include <cst

POJ 1787 Charlie&amp;#39;s Change

多重背包 可行性+路径记录 题意是说你要用很多其它的零钱去买咖啡.最后输出你分别要用的 1,5 ,10 .25 的钱的数量. 多重背包二进制分解.然后记录下 这个状态.最后逆向推就可以. #include<cstdio> #include<cstring> #include<string> #include<queue> #include<algorithm> #include<map> #include<stack> #

POJ - 1787 (多重背包还原路径|| 完全背包)

POJ  1787  Charlie's Change Description Charlie is a driver of Advanced Cargo Movement, Ltd. Charlie drives a lot and so he often buys coffee at coffee vending machines at motorests. Charlie hates change. That is basically the setup of your next task

poj 1787 背包+记录路径

http://poj.org/problem?id=1787 Charlie's Change Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 4512   Accepted: 1425 Description Charlie is a driver of Advanced Cargo Movement, Ltd. Charlie drives a lot and so he often buys coffee at co

(多重背包+记录路径)Charlie&#39;s Change (poj 1787)

http://poj.org/problem?id=1787 描述 Charlie is a driver of Advanced Cargo Movement, Ltd. Charlie drives a lot and so he often buys coffee at coffee vending machines at motorests. Charlie hates change. That is basically the setup of your next task. Your

Charlie&#39;s Change POJ - 1787 (完全背包+记录路径)

完全背包输出路径:对于每一次更新记录一下路径:注意钱币个数: dp[i][0]代表在空间为i时需要多少枚钱币 dp[i][1]用来记录路径 cheek[j]用来记录在j时用了多少i枚钱币 思路在代码中: #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define mem(a,b) memset(a,b,sizeof

POJ Charlie&#39;s Change 查理之转换(多重背包,微变形)

题意:给定身上的4种硬币,分别是1 ,5 ,10, 25面额各有多张,要求组成面额p的硬币尽可能多.输出组成p的4种硬币各自的数量. 思路:多重背包,300+ms.用01背包+二进制的方法.记录下所有的硬币的个数以及4种硬币分别的个数,注意初始化dp数组的不同之处. 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #define LL long long 5 using namespace

zoj 2156 - Charlie&#39;s Change

题目:钱数拼凑,面值为1,5,10,25,求组成n面值的最大钱币数. 分析:dp,01背包.需要进行二进制拆分,否则TLE,利用数组记录每种硬币的个数,方便更新. 写了一个 多重背包的 O(NV)反而没有拆分快.囧,最后利用了状态压缩优化 90ms: 把 1 cents 的最后处理,其他都除以5,状态就少了5倍了. 说明:貌似我的比大黄的快.(2011-09-26 12:49). #include <stdio.h> #include <stdlib.h> #include <

Charlie&#39;s Change(完全背包+路径记忆)

Charlie's Change Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 3176   Accepted: 913 Description Charlie is a driver of Advanced Cargo Movement, Ltd. Charlie drives a lot and so he often buys coffee at coffee vending machines at motores