《挑战程序设计竞赛》上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. oracle数据库rownum讲解(转)

    https://blog.csdn.net/qq_40794266/article/details/78698321

  2. hdu3887 Counting Offspring

    Counting Offspring HDU - 3887 问你对于每个节点,它的子树上标号比它小的点有多少个 /* 子树的问题,dfs序可以很轻松的解决,因为点在它的子树上,所以在线段树中,必定在它 ...

  3. avro-maven-plugin

    <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://mave ...

  4. 【手撸一个ORM】第十步、数据操作工具类 MyDb

    说明 其实就是数据库操作的一些封装,很久不用SqlCommand操作数据库了,看了点园子里的文章就直接上手写了,功能上没问题,但写法上是否完美高效无法保证,建议有需要的朋友自己重写,当然如果能把最佳实 ...

  5. Jenkins之自动触发部署之插件Generic Webhook Trigger Plugin

    一.安装好插件 二.构建触发器会出现设置trigger的入口 三.设置的两个部分 第一: Jenkins的这个触发器,这里主要是接受post数据.其中Post content parameters是用 ...

  6. lecture-7 递归

    1.例题--排列 Permutation Given a collection of distinct numbers, return all possible permutations.For ex ...

  7. Java面向对象_包装类访问修饰符

    在java中有一个设计的原则"一切皆对象",java中的基本数据类型就完全不符合这种设计思想,因为八种基本数据类型并不是引用数据类型,所以java中为了解决这样的问题,jdk1.5 ...

  8. css 设置table样式

    <style type="text/css" >      table tr td{height:39px; font-size: 13px; line-height: ...

  9. ERROR [org.apache.hadoop.util.Shell] - Failed to locate the winutils binary in the hadoop binary path

    错误日志如下: -- ::, DEBUG [org.apache.hadoop.metrics2.lib.MutableMetricsFactory] - field org.apache.hadoo ...

  10. Zipkin — 微服务链路跟踪.

    一.Zipkin 介绍 Zipkin 是什么?  Zipkin的官方介绍:https://zipkin.apache.org/  Zipkin是一款开源的分布式实时数据追踪系统(Distributed ...