《挑战程序设计竞赛》上DP的一道习题。

很裸的多重背包。下面对比一下方法,倍增,优化定义,单调队列。

一开始我写的倍增,把C[i]分解成小于C[i]的2^x和一个余数r。

dp[i][j]的定义前i个数字能否到凑出j来,改成一位滚动数组。

#include<cstdio>
#include<iostream>
#include<string>
#include<cstring>
#include<queue>
#include<vector>
#include<stack>
#include<vector>
#include<map>
#include<set>
#include<algorithm>
//#include<bits/stdc++.h>
using namespace std; #define PS push
#define PB push_back
#define MP make_pair
#define fi first
#define se second const int maxm = 1e5+;
const int maxn = ; bool dp[maxm]; int A[maxn], C[maxn]; int n, m; inline int read()
{
int ret; char c; while(c = getchar(),c<''||c>'');
ret = c-'';
while(c = getchar(),c>=''&&c<='') ret = ret* + c-'';
return ret;
} //#define LOCAL
int main()
{
#ifdef LOCAL
freopen("in.txt","r",stdin);
#endif
dp[] = true;
while(scanf("%d%d",&n,&m),n+m){
for(int i = ; i < n; i++)
A[i] = read();
for(int i = ; i < n; i++){
C[i] = read();
}
memset(dp+,,sizeof(bool)*m);
for(int i = ; i < n; i++){
int b = ,vol = A[i];
while((<<b)<=C[i]+){ //11...111 (b) <= C[i] -> 100.... <= C[i]+1
for(int S = m; S >= vol; S--){
dp[S] = dp[S-vol]||dp[S];
}
b++; vol<<=;
}
int r = C[i]-(<<(b-))+;
if(r){
int Vol = A[i]*r;
for(int S = m; S >= Vol; S--){
dp[S] = dp[S-Vol]||dp[S];
}
}
}
int ans = ;
for(int i = ; i <= m; i++) ans += dp[i];
printf("%d\n",ans);
}
return ;
}

binary

复杂度是O(n*m*sigma(logC[i]))。然后果断就TLE了。

再优化只有单调队列了,扎扎并没有想到怎么用单调队列。

书上的解法是优化定义,同样的时间复杂度记录bool信息太浪费了。

dp[i][j]表示前i种凑出面值j时第i种硬币最多的剩余。

核心代码:

        int ans = ;
memset(dp+,-,sizeof(int)*m);
for(int i = ; i < n; i++){
for(int j = ; j <= m; j++){
if(~dp[j]) dp[j] = C[i]; //之前凑出了j
else if(j >= A[i] && dp[j-A[i]]>) { //还可以在凑
dp[j] = dp[j-A[i]] - ;
ans++;
}else dp[j] = -; //凑不出
}
}

跑了1985ms。

另外还发现一件有意思的事情,

当我用一个临时变量数组cnt[j]记录凑出j的最小次数的时候,跑了1235ms。(系统分配似乎更快一点?

        int ans = ;
memset(dp+,,sizeof(bool)*m);
for(int i = ; i < n; i++){
int cnt[maxm] = {};
for(int j = A[i]; j <= m; j++){
if(!dp[j] && dp[j-A[i]] && cnt[j-A[i]] < C[i]){
cnt[j] = cnt[j-A[i]] + ;
ans++;
dp[j] = true;
}
}
}

参考了http://www.cnblogs.com/xinsheng/archive/2013/12/04/3458362.html之后,明白了单调队列的做法的。

总体来说是划分同余类,对于一个同余类用单调队列维护滑动窗口的最小值。(左端为最多减去C[i]个物品的的状态

这道题只要判断存在性,连单调性都用不上(insert不需要删除队尾元素),只要维护滑动窗口的和以及大小就可以了。

但是这道题数据丧心病狂,直接分组常数比较大TLE了。我改成判断0-1和完全才2891 ms飘过(常数写丑了

int ans = ;
memset(dp+,,sizeof(bool)*m);
for(int i = ; i < n; i++){
if(C[i] == ){
for(int j = m; j >= A[i]; j--){
dp[j] = dp[j-A[i]] || dp[j];
}
}
else if(A[i]*C[i] >= m){
for(int j = A[i]; j <= m; j++){
dp[j] = dp[j-A[i]] || dp[j];
}
}
else {
for(int r = ; r < A[i]; r++){
int sum = , hd = , rr = ;
for(int j = r; j <= m; j += A[i]){
if(rr - hd > C[i]){
sum -= q[hd++];
}
sum += q[rr++] = dp[j];
if(sum) dp[j] = true;
}
}
}
}
for(int i = ; i <= m; i++) ans += dp[i];

似乎完全的情况比较多的情况,我只改了一个语句的不同结果。。

dp[j] = dp[j-A[i]] || dp[j]; 2891 ms

if(dp[j-A[i]]) dp[j] = true; 2813 ms

if(dp[j-A[i]] && !dp[j]) dp[j] = true; 2110 ms

POJ 1742 Coins(多重背包,优化)的更多相关文章

  1. POJ 1742 Coins(多重背包, 单调队列)

    Description People in Silverland use coins.They have coins of value A1,A2,A3...An Silverland dollar. ...

  2. POJ 1742 Coins (多重背包)

    Coins Time Limit: 3000MS   Memory Limit: 30000K Total Submissions: 28448   Accepted: 9645 Descriptio ...

  3. poj 1742 coins_多重背包

    题意:给你N个种硬币,价值和数量,知道手表不大于m,问能组成(1~m)的价格有多少种情况 套套上次那题的模板直接就行了,http://blog.csdn.net/neng18/article/deta ...

  4. POJ 3260 The Fewest Coins(多重背包+全然背包)

    POJ 3260 The Fewest Coins(多重背包+全然背包) http://poj.org/problem?id=3260 题意: John要去买价值为m的商品. 如今的货币系统有n种货币 ...

  5. hdu 2844 poj 1742 Coins

    hdu 2844 poj 1742 Coins 题目相同,但是时限不同,原本上面的多重背包我初始化为0,f[0] = 1;用位或进行优化,f[i]=1表示可以兑成i,0表示不能. 在poj上运行时间正 ...

  6. poj 1742 Coins(二进制拆分+bitset优化多重背包)

    \(Coins\) \(solution:\) 这道题很短,开门见山,很明显的告诉了读者这是一道多重背包.但是这道题的数据范围很不友好,它不允许我们直接将这一题当做01背包去做.于是我们得想一想优化. ...

  7. poj 1742 Coins(二进制优化多重背包)

    传送门 解题思路 多重背包,二进制优化.就是把每个物品拆分成一堆连续的\(2\)的幂加起来的形式,然后把最后剩下的也当成一个元素.直接类似\(0/1\)背包的跑就行了,时间复杂度\(O(nmlogc) ...

  8. poj 1742 Coins (多重背包)

    http://poj.org/problem?id=1742 n个硬币,面值分别是A1...An,对应的数量分别是C1....Cn.用这些硬币组合起来能得到多少种面值不超过m的方案. 多重背包,不过这 ...

  9. Poj 1742 Coins(多重背包)

    一.Description People in Silverland use coins.They have coins of value A1,A2,A3...An Silverland dolla ...

随机推荐

  1. [Windows]获取当前时间(年/月/日/时/分/秒)

    struct tm* GetCurTime(time_t inTime) { struct tm* curTime = localtime(&inTime); curTime->tm_y ...

  2. Hadoop 对MapReduce的理解

    对MapReduce的理解 客户端启动一个作业 向JobTraker请求一个JobId 将资源文件复制到HDFS上,包括Jar文件,配置文件,输入划分信息等 接收作业后,进入作业队列,根据输入划分信息 ...

  3. 创建、配置Servlet

    1.创建Servlet 2.选择继承的类及需要覆盖的方法 3.Servlet结构 package com.sysker.servlet; import java.io.IOException; imp ...

  4. 菜鸟眼中的”AppSettings和ConnectionStrings“

    前言 这次的机房收费系统重构,我们用到了这个配置文件.瞬间感觉高大上了许多,对新鲜的事务就是又陌生又好奇,通过看静静的博客,还有自己查资料花了点时间弄了弄,下面是我整理的结果. 内容 是什么 AppS ...

  5. 51nod1118(递推)

    题目链接: https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1118 题意: 中文题诶~ 思路: 因为机器人只能往下或者右 ...

  6. 背包DP【bzoj2287】: 【POJ Challenge】消失之物

    2287: [POJ Challenge]消失之物 Description ftiasch 有 N 个物品, 体积分别是 W1, W2, ..., WN. 由于她的疏忽, 第 i 个物品丢失了. &q ...

  7. php静态方法和属性

    静态方法和属性由static关键字定义 静态方法和属性不用实例化也可以直接访问,如 self::test(),self::tt 类实例化后可以访问静态方法,但是不可以访问静态属性 声明类属性或方法为静 ...

  8. jmeter使用BeanShell Sampler测试自己写的java接口(一)

    上次直接使用jmeter里面的FTPsampler没有连接成功 现在想着自己写java代码,通过jmeter进行调用进行连接测试实现并发 代码引文: http://www.cnblogs.com/ch ...

  9. js——移动端js事件、zepto.js

    1. touchstart : 手指放到屏幕上时触发 2. touchmove : 手指在屏幕上滑动时触发 3. touched : 手指离开屏幕时触发 4. touchcancel : 系统取消to ...

  10. Silverlight Telerik 学习之主题的设置

    Telerik控件版本:RadControls for Silverlight Q1 2013 当前的Telerik Silverlight 控件支持以下主题 Office Black - 这是默认主 ...