多重背包的题目很多,最著名的是poj1742楼教主的男人八题之一。

poj1742:coins

有几种面值的钱币和每种的数量,问能够组成m以内的多少种钱数

这个题大家都归为多重背包问题,不过跟实际意义上的背包还是有所差别的

因为如果把钱币看作背包中的物品,那么这个物品的价值和重量是相等的。

也就是没有“性价比"的。。

一种比较快速简单的做法是:

在判断能否放满某个体积时,如果能放满,尽量少用当前物品,贪心一下,对当前物品最优即可。

也可以用dp的思路想,就是dp[i][j]保存 j 体积最少用多少个物品 i

状态转移很明显:如果 dp[i-1][j] 合法 那么显然 dp[i][j]=0,否则在判断dp[i][j]能否由dp[i][j-w[i]]+1得到

复杂度O(N*M),而且常数也很小,可以通过楼教主的题目

两种代码如下:

#include <iostream>
#include <stdio.h>
#include<string.h>
#include<algorithm>
#include<string>
#include<ctype.h>
using namespace std;
int num[];
bool dp[];
int a[];
int c[];
int n,m;
int main()
{
freopen("in.txt","r",stdin);
//int T,cas=0;
//scanf("%d",&T);
//while(T--)
while(scanf("%d%d",&n,&m),n+m)
{
//cas++;
//scanf("%d%d",&n,&m);
for(int i=;i<=n;i++)
scanf("%d",a+i);
for(int i=;i<=n;i++)
scanf("%d",c+i);
memset(dp,,sizeof(dp));
dp[]=;
for(int i=;i<=n;i++)
{
memset(num,,sizeof(num));
for(int j=a[i];j<=m;j++)
{
if(num[j-a[i]]>=c[i])
continue;
if(dp[j]||(!dp[j-a[i]]))
continue;
num[j]=num[j-a[i]]+;
dp[j]=;
}
}
int ans=;
for(int i=;i<=m;i++)
{
ans+=dp[i];
}
//printf("Case %d: %d\n",cas,ans);
printf("%d\n",ans);
}
return ;
}
#include <iostream>
#include <stdio.h>
#include<string.h>
#include<algorithm>
#include<string>
#include<ctype.h>
using namespace std;
int dp[];
int a[];
int c[];
int n,m;
int main()
{
//freopen("in.txt","r",stdin);
while(scanf("%d%d",&n,&m),n+m)
{
for(int i=;i<=n;i++)
scanf("%d",a+i);
for(int i=;i<=n;i++)
scanf("%d",c+i);
memset(dp,-,sizeof(dp));
dp[]=;
int ans=;
for(int i=;i<=n;i++)
{
for(int j=;j<=m;j++)
{
if(dp[j]!=-)
{
dp[j]=;
}
else if(j>=a[i]&&dp[j-a[i]]!=-&&dp[j-a[i]]<c[i])
{
dp[j]=dp[j-a[i]]+;
}
}
}
for(int i=;i<=m;i++)
{
ans+=(dp[i]!=-);
}
printf("%d\n",ans);
}
return ;
}

但是物品如果重量和价值不同,那么以上方法就不行了。。
以上方法的策略是对某一个价值,尽量少选当前物品,但是我们又知道背包问题中,我们要尽量使达到某一个价值时所用的重量最小

这两个策略显然是会出现矛盾的。

下面我们来看一下这种情况的解决方法:

先按照传统背包问题的写法,写出朴素dp方程:

dp[i][j]=max(dp[i-1][j-k*w[i]]+k*v[i])  其中0<=k<=c[i]

显然这个方程的复杂度是 n*v*c 的。数据稍大就会超时,那么怎么优化呢

求最值的dp优化,首先想到是单调队列优化,但是这个方程貌似更单调队列无关

尝试把它变形

我们令 r=j%w[i] , p=j/w[i]

则以上方程变为

dp[i][ p*w[i]+r ]=dp[i-1][ (p-k)*w[i] + r]+k*v[i]。

为了观察方便,再令 k=p-k,并移项,得到

dp[i][ p*w[i]+ r]-p*v[i] =dp[i-1][k*w[i]+r]-k*v[i]  其中对于特定的p,k属于 [p-c[i] , p]。

这个式子就跟简单的单调队列优化dp的式子很像了。。

把k当作单调队列下标,对于[ 0,w[i]-1 ]的每一个r,枚举k,建立一个单调队列,就可以完成状态转移了

由于单调队列复杂度是O(n)

总复杂度即为 O(n*r*p)=O(n*m)

不过这个通用的做法由于常数过大。。我的程序没过楼教主的那道题,感人的TLE了一晚上

也不知道到底慢了多少

后来我百度了很多这道题单调队列的题解发现是用单调队列的写法去填bool数组。我感觉本质上和第一种方法没什么差别。所以就不纠结了= =

贴上第二种做法的核心代码:

for(i=; i<=n; ++i)
{
int p=m/w[i];
for(j=w[i]-; j+; --j)
{
s=e=;
for(int k=p; k+; --k)
{
if(k*w[i]+j>m)
continue
node tmp;
tmp.num=k;
int tt=tmp.val=dp[k*w[i]+j]-k*v[i];
int x;
if(tt>=q[s].val)
{
s=e=;
}
else
{
for(x=e-; x>=s&&tt>=q[x].val; --x);
e=x+;
}
q[e++]=tmp; //入队
}
//由于压缩到一维背包需要从大到小循环,故先将能转移到 k=p的所有状态入队
for(int k=p; k+; --k)
{
if(k*w[i]+j>m)
continue;
node tmp;
int x;
if(k>=c[i])
{
tmp.num=k-c[i];
int tt=tmp.val=dp[(k-c[i])*w[i]+j]-(k-c[i])*v[i];
if(tt>=q[s].val)
{
s=e=;
}
else
{
for(x=e-; x-s+&&tt>=q[x].val; --x);
e=x+;
}
q[e++]=tmp;
} //入队
for(x=s; e-x&&q[x].num>k; ++x);
s=x; //出队
dp[k*w[i]+j]=q[s].val+k*v[i];
}
}
}

多重背包问题的两种O(M*N)解法的更多相关文章

  1. hdu2844 &amp; poj1742 Coin ---多重背包--两种方法

    意甲冠军:你有N种硬币,每个价格值A[i],每个号码C[i],要求. 在不超过M如果是,我们用这些硬币,有多少种付款的情况下,.那是,:1,2,3,4,5,....,M这么多的情况下,,你可以用你的硬 ...

  2. 多重背包问题:悼念512汶川大地震遇难同胞——珍惜现在,感恩生活(HDU 2191)(二进制优化)

    悼念512汶川大地震遇难同胞——珍惜现在,感恩生活 HDU 2191 一道裸的多重背包问题: #include<iostream> #include<algorithm> #i ...

  3. 5. 多重背包问题 II 【用二进制优化】

    多重背包问题 II 描述 有 NN 种物品和一个容量是 VV 的背包. 第 ii 种物品最多有 sisi 件,每件体积是 vivi,价值是 wiwi. 求解将哪些物品装入背包,可使物品体积总和不超过背 ...

  4. 4. 多重背包问题 I

    多重背包问题 I 描述 有 NN 种物品和一个容量是 VV 的背包. 第 ii 种物品最多有 sisi 件,每件体积是 vivi,价值是 wiwi. 求解将哪些物品装入背包,可使物品体积总和不超过背包 ...

  5. C语言-多重背包问题

    多重背包问题 问题:有N种物品和一个容量为V的背包.第i种物品最多有n[i]件可用,每件费用是c[i],价值是w[i].求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大. 分 ...

  6. O(V*n)的多重背包问题

    多重背包问题: 有n件物品,第i件价值为wi,质量为vi,有c1件,问,给定容量V,求获得的最大价值. 朴素做法: 视为0,1,2,...,k种物品的分组背包 [每组只能选一个] f[i][j]=Ma ...

  7. 什么是CS和BS结构,两种结构的区别

    什么是CS和BS结构,两种结构的区别 什么是C/S和B/S结构?         C/S又称Client/Server或客户/服务器模式.服务器通常采用高性能的PC.工作站或小型机,并采用大型数据库系 ...

  8. I/O模型系列之四:两种高性能IO设计模式 Reactor 和 Proactor

    不同的操作系统实现的io策略可能不一样,即使是同一个操作系统也可能存在多重io策略,常见如linux上的select,poll,epoll,面对这么多不同类型的io接口,这里需要一层抽象api来完成, ...

  9. POJ 3260 The Fewest Coins(多重背包问题, 找零问题, 二次DP)

    Q: 既是多重背包, 还是找零问题, 怎么处理? A: 题意理解有误, 店主支付的硬币没有限制, 不占额度, 所以此题不比 1252 难多少 Description Farmer John has g ...

随机推荐

  1. CSS常用操作-分类

  2. iOS面试题大全-点亮你iOS技能树

    所有的内容大部分来自于网络的搜集,所以我不是一个创造者,而是一个搬运工.我尽量把题目,尤其是参考答案的出处列明.若有任何疑问,建议,意见,请联系我. 第一部分面试题来源于iOS-Developer-I ...

  3. C++编程规范之19:总是初始化变量

    摘要: 一切从白纸开始,未初始化的变量是C和C++程序中错误的常见来源.养成在使用内存之前先清除的习惯,可以避免这种错误,在定义变量的时候就将其初始化. 按照C和C++相同的低层高效率传统,通常并不要 ...

  4. 自适应网页设计(Responsive Web Design)(转)

    作者: 阮一峰 出处:http://www.ruanyifeng.com/blog/2012/05/responsive_web_design.html 随着3G的普及,越来越多的人使用手机上网. 移 ...

  5. poj 3181 Dollar Dayz (整数划分问题---递归+DP)

    题目:http://poj.org/problem?id=3181 思路:将整数N划分为一系列正整数之和,最大不超过K.称为整数N的K划分. 递归:直接看代码: 动态规划:dp[i][j]:=将整数i ...

  6. HTML 5 与HTML 4 的区别

    (1)HTML 5 与HTML 4 的相比,语法的改变,以下四个方面: 字符编码改变举例: 省略标记值: (2)新增和废弃的元素 (3)新增html全局属性 (1)指定元素是否可编辑 (2)指定页面是 ...

  7. iOS 使用GitHub托管代码(github desktop使用)

    iOS 使用GitHub托管代码 代码托管 1.首先得有一个GitHub的账号,没有的话就去https://github.com注册一个吧. 2.下载GitHub Mac客户端:http://mac. ...

  8. 高性能ORM框架XLinq功能详细介绍

    之前简单介绍了XLinq的一些功能,有很多功能都没有提到,现在给XLinq加了一些功能,这次把所有功能都介绍一遍. 设计目标 易用性 在使用一个框架的时候 应该没几个人会喜欢写一大堆的配置文件吧 也应 ...

  9. javascrip中setTimeout和setInterval

    1: http://www.jb51.net/article/68258.htm 2: http://www.jb51.net/article/26679.htm

  10. Web项目中JSP页面的一种调试方法与出现的问题 -- SpringMVC架构测试

    在前端开发中,尤其是MVC架构多人开发,负责前端的童鞋总是需要做静态页面,再和后台连接前无法使用变量如EL表达式等测试功能,所以本人引入了一个模板jsp数据测试专用文件,专门配置所有的变量,然后在待测 ...