博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
单调队列优化多重背包
阅读量:4590 次
发布时间:2019-06-09

本文共 989 字,大约阅读时间需要 3 分钟。

回顾多重背包

有n种物品,用大小为m的包来装,问获取的最大价值为多少。其中,第 i 种物品的重量,价值,个数分别为 w[i],v[i],c[i].

那么,若f[i][j]表示考虑前 i 种物品,使用 j 的背包可获取的最大价值,状态转移方程为

for(int i=1;i<=n;i++)

  for(int k=1;k<=c[i];k++)

    for(int j=0;j<=m;j++)

      if(j-k*w[i]>=0)f[i][j]=max(f[i-1][j],f[i-1][j-k*w[i])+v[i]);

      else f[i][j]=f[i-1][j];

单调队列优化

考虑到,f[i][j1]可由f[i-1][j2]更新当且仅当j1,j2模w[i]同余。

那么,要更新每个f[i][j],只用在 j' 模w[i]同余地一系列f[i-1][j']中找,而且这一系列数的 j' 有都相差w[i],所以可以用一个单调队列来保存离 j 最近的c[i]个 j' 的最大值,队首保存用于更新的最优解,就可以直接找到最优的更新方案。

对于进队的条件:

由于放同一种物品空间与价值成正比,则f[i-1][j]可以更新的背包空间为一条斜线段所覆盖的区域,起点即为点(j,f[i-1][j]),斜率即为价值比总量,而队中存的就是起点(我存了起点的横坐标)。若当前有要入队的起点,可以做如第一个图的比较,使用当前起点更新的范围是否涵盖了队尾元素,若涵盖了则弹出,否则将当前起点加入队中。

对于出队条件:当前要更新的背包空间已经超出了队首的最远更新范围。

HDU2191代码

这个题其实可以不加优化:-)

1 #include
2 using namespace std; 3 int C,n,m,a[101],b[101],c[101],f[101][101]; 4 int dui[100000],hd,tl; 5 6 bool calc(int kj,int wp) 7 { 8 int maxa=c[wp]*a[wp]; 9 int tem=dui[hd+1];10 if(tem+maxa

 

转载于:https://www.cnblogs.com/LiqgNonqfu/p/10800929.html

你可能感兴趣的文章
linux程序对比
查看>>
linux数码管驱动程序和应用程序
查看>>
linux在菜单中添加SEG选项
查看>>
linux物理地址和虚拟地址
查看>>
linux驱动程序与菜单关联
查看>>
linux在配置菜单中添加选项
查看>>
linux修改文件系统注册设备
查看>>
linux添加地址映射
查看>>
c#程序集
查看>>
Microsoft 中间语言
查看>>
.NET Framework 简介
查看>>
c#通用语言运行时CLR
查看>>
编译和执行 C# 应用程序
查看>>
c#命名空间
查看>>
c#字面量
查看>>
C# 应用程序文件夹结构
查看>>
c# Format() 方法
查看>>
c#实例
查看>>
c# Format() 方法
查看>>
c# String 常用方法应用
查看>>