所以说这就是一篇写炸的废文!!!!

所以说背包直接看dd大神的就好了,算了瞎写写吧。

0/1背包

有n件物品和一个容量为C的背包。第i件物品的重量是w[i],价值是v[i]。求解将哪些物品放入背包可使背包的价值总和最大。

0/1背包是最基础的背包问题,问题的特点是:每种物品只有一件,那么对于第i种物品一共只存在两个状态:取或不取。

定义状态:用f[i][c] 表示前i件物品恰放入一个容量为v的背包可以获得的最大价值。

那么很容易可以得到状态转移方程:

f[i][j]=max{ f[i-1][c] , f[i-1][c-w[i]]+v[i] }

这个方程非常重要,基本上所有跟背包相关的问题的方程都是由它衍生出来的。所以有必要将它详细解释一下:“将前i件物品放入容量为v的背包中”这个子问题,若只考虑第i件物品的策略(放或不放),那么就可以转化为一个只牵扯前i-1件物品的问题。

如果不放第i件物品,那么问题就转化为“前i-1件物品放入容量为v的背包中”,价值为f[i-1][v]; 如果放第i件物品,那么问题就转化为“前i-1件物品放入剩下的容量为v-c[i]的背包中”,此时能获得的最大价值就是f[i-1][v-c[i]]再加上通过放入第i件物品获得的价值w[i]。(以上两段话来自dd神犇博客)

据dd神犇所讲,对于上述方程,时间复杂度和空间复杂度为O(N*V),时间复杂度已经无法优化,而空间复杂度可以优化;具体操作详见dd大神博客。

①    百度—搜索背包九讲—找一个写的最强大的CSDN博客

②    传送门:http://blog.csdn.net/ling_du/article/details/41594767(搬运)

回到正题,虽然我是讲不清楚(早晚弄懂回来讲一遍)代码还是要放的

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

for(int c=C;c>=w[i];c--)

f[c]=max(f[c],f[c-w[i]]+v[i]);

}

需要注意的是,第二层循环的顺序十分重要,如果写成顺推,就会出现已经更新过的状态被重复更新,实际上这可以用来解决完全背包,那么如何才能让每个状态只被更新一次?逆推。我们想一下,我们所写的方程,利用的是c-w[i],如果正着推,不可避免的会出现c-w[i]=之前被更新过的某个状态,但倒着显然就不会,因为c-w[i]是越变越小的,这样就达到了每个物品只取一次的目的。当然…这是我yy+显然的证明法,具体解释还是去dd神犇博客慢慢看吧。

完全背包

有N种物品和一个容量为V的背包,每种物品都有无限件可用。第i种物品的费用是c[i],价值是w[i]。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。

对于完全背包,它和0/1背包的区别就在于0/1背包的每件物品只能用一次,而完全背包每件物品可以使用无限次。基本解法就是将它转变成0/1背包来解,相较于0/1背包,似乎要多枚举一层件数?

状态转移方程:

f[i][v]=max{f[i-1][v-k*c[i]]+k*w[i]|0<=k*c[i]<=v}

这跟01背包问题一样有O(N*V)个状态需要求解,但求解每个状态的时间已经不是常数了,求解状态f[i][v]的时间是O(v/c[i]),总的复杂度是超过O(VN)的。

将01背包问题的基本思路加以改进,得到了这样一个清晰的方法。这说明01背包问题的方程的确是很重要,可以推及其它类型的背包问题。但我们还是试图改进这个复杂度。(来自dd神犇)。

还记得0/1背包中被我yy+显然得出的结论吧…..

没错!0/1背包简化成一维后的第二重循环我们只要把逆推改为正推就行!既然完全背包需要重复计算,那我们就用曾经被我们否决掉的能用来重复计算的方案就好。(更严谨的解释…你们知道我要让你们看什么)。

代码:

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

for(int c=w[i];c<=C;c++)

if[c]=max( f[c] , f[c-w[i]] + v[i]);

}

/*来自dd神犇博客:完全背包问题有一个很简单有效的优化,是这样的:若两件物品i、j满足c[i]<=c[j]且w[i]>=w[j],则将物品j去掉,不用考虑。这个优化的正确性显然:任何情况下都可将价值小费用高得j换成物美价廉的i,得到至少不会更差的方案。对于随机生成的数据,这个方法往往会大大减少物品的件数,从而加快速度。然而这个并不能改善最坏情况的复杂度,因为有可能特别设计的数据可以一件物品也去不掉。

这个优化可以简单的O(N^2)地实现,一般都可以承受。另外,针对背包问题而言,比较不错的一种方法是:首先将费用大于V的物品去掉,然后使用类似计数排序的做法,计算出费用相同的物品中价值最高的是哪个,可以O(V+N)地完成这个优化。*/

多重背包

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

和完全背包类似的问题,除了每件物品有固定件数,循环改一下即可,方程:

f[i][v]=max{f[i-1][v-k*c[i]]+k*w[i]|0<=k<=n[i]}

没错就只是加了一个数量限制而已。

然后我们想着试图优化这个方程。

转化为01背包问题

另一种好想好写的基本方法是转化为01背包求解:把第i种物品换成n[i]件01背包中的物品,则得到了物品数为Σn[i]的01背包问题,直接求解,复杂度仍然是O(V*Σn[i])。

但是我们期望将它转化为01背包问题之后能够像完全背包一样降低复杂度。仍然考虑二进制的思想,我们考虑把第i种物品换成若干件物品,使得原问题中第i种物品可取的每种策略——取0..n[i]件——均能等价于取若干件代换以后的物品。另外,取超过n[i]件的策略必不能出现。

方法是:将第i种物品分成若干件物品,其中每件物品有一个系数,这件物品的费用和价值均是原来的费用和价值乘以这个系数。使这些系数分别为1,2,4,...,2^(k-1),n[i]-2^k+1,且k是满足n[i]-2^k+1>0的最大整数。例如,如果n[i]为13,就将这种物品分成系数分别为1,2,4,6的四件物品。

分成的这几件物品的系数和为n[i],表明不可能取多于n[i]件的第i种物品。另外这种方法也能保证对于0..n[i]间的每一个整数,均可以用若干个系数的和表示,这个证明可以分0..2^k-1和2^k..n[i]两段来分别讨论得出,例如:

13=2^0+2^1+2^2+6

对于件数足够多的,我们可以将它视为完全背包来写。代码:

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

if(w[i]*a[i]>C){

for(int c=0;c<=C;c++)

if(c>=w[i])

f[c]=max(f[c],f[c-w[i]]+v[i]);

}

else{

int k=1,amount=a[i];

while(k<amount){//想一想刚才说的二进制法

for(int c=C;c>=k*w[i];c--)

f[c]=max(f[c],f[c-k*w[i]]+k*v[i]);

amount-=k;

k+=k;

}

for(int c=C;c>=amount*w[i];c--)//把剩下的当成一个物品

f[c]=max(f[c],f[c-amount*w[i]]+amount*v[i]);

}

}

混合背包

简而言之,将以上三种背包混在一起,判断一下是哪个背包即可

for(int i=1;i<=n;i++){
  if(num[i]==1){//0/1
    for(int c=v1;c>=w[i];c--)
      f[c]=max(f[c],f[c-w[i]]+v[i]);
  }
  else if(num[i]*w[i]>v1){//完全
    for(int c=w[i];c<=v1;c++)
      f[c]=max(f[c],f[c-w[i]]+v[i]);
  }
  else {//多重
    int k=1,amount=num[i];
    while(k<amount){
      for(int c=v1;c>=k*w[i];c--)
        f[c]=max(f[c],f[c-k*w[i]]+k*v[i]);
      amount-=k;
      k<<=1;
    }
    for(int c=v1;c>=amount*w[i];c--)
    f[c]=max(f[c],f[c-amount*w[i]]+amount*v[i]);
  }
}

 

蒟蒻的9个背包的浩大工程(更新中)(无限延期)(太长了不舍删虽然写的lj的一匹)的更多相关文章

  1. [New!!!]欢迎大佬光临本蒟蒻的博客(2019.11.27更新)

    更新于2019.12.22 本蒟蒻在博客园安家啦!!! 本蒟蒻的博客园主页 为更好管理博客,本蒟蒻从今天开始,正式转入博客园. 因为一些原因,我的CSDN博客将彻底不会使用!!!(带来不便,敬请谅解) ...

  2. 【杂文】NOIP2018 蒟蒻自闭记

    [杂文]NOIP2018 蒟蒻自闭记 都 \(9102\) 年了,谁还记得 \(2018\) 年的事啊 \(QAQ\) . 还有两个月就要去参加首届 \(CSP\) 了. 想着如果再不记下去年那些事儿 ...

  3. NOIp蒟蒻的爆零记——HA-0132

    考前: 从十一月开始的听课集训,连考六场:考前的最后两天写(da)着(zhe)各种各样的奇(C)葩(S)模板:一周的疯狂,已经过去: 考前的一晚:第二批高二的六个人聚在一起(还有滑稽大师),愉快的玩( ...

  4. 【BZOJ-4636】蒟蒻的数列 动态开点线段树 ||(离散化) + 标记永久化

    4636: 蒟蒻的数列 Time Limit: 30 Sec  Memory Limit: 256 MBSubmit: 247  Solved: 113[Submit][Status][Discuss ...

  5. 【蒟蒻の进阶PLAN】 置顶+持续连载

    看到周围神犇们纷纷列计划,本蒟蒻也决定跟随他们的步伐,计划大约是周计划吧,具体怎么安排我也不确定.. 2015.12.30 刚刚学习完最基础的网络流,需要进行这方面的练习,从简到难,有空余的话尝试学习 ...

  6. [BZOJ4636]蒟蒻的数列

    [BZOJ4636]蒟蒻的数列 试题描述 蒟蒻DCrusher不仅喜欢玩扑克,还喜欢研究数列 题目描述 DCrusher有一个数列,初始值均为0,他进行N次操作,每次将数列[a,b)这个区间中所有比k ...

  7. 蒟蒻修养之cf橙名计划

    因为太弱,蒟蒻我从来没有上过div1(这就是今年的最后愿望啊啊啊啊啊)已达成................打cf几乎每次都是fst...........所以我的cf成绩图出现了惊人了正弦函数图像.. ...

  8. 【BZOJ】4636: 蒟蒻的数列

    4636: 蒟蒻的数列 Time Limit: 30 Sec  Memory Limit: 256 MBSubmit: 145  Solved: 71[Submit][Status][Discuss] ...

  9. noip2013Day2T3-华容道【一个蒟蒻的详细题解】

    描述 小 B 最近迷上了华容道,可是他总是要花很长的时间才能完成一次.于是,他想到用编程来完成华容道:给定一种局面,华容道是否根本就无法完成,如果能完成,最少需要多少时间. 小 B 玩的华容道与经典的 ...

随机推荐

  1. IIS 发布后无法连接数据库(应用池问题)

    查找网站对应的  应用池,修改为 .net4.0  然后设置启动32位应用程序为 True

  2. Codeforces Round #553 F Sonya and Informatics

    题目 题目大意 给定一个长为 $n$($2 \le n \le 100$)的01串 $S$ .对 $S$ 进行 $k$($1 \le k \le 10^9$)次操作:等概率地选取两个下标 $i, j$ ...

  3. JavaScript(二):对象、注释、事件!

    对象 JavaScript的一个重要功能就是面向对象的功能,通过基于对象的程序设计,可以用更直观.模块化和可重复使用的方式进行程序开发. 一组包含数据的属性和对属性中包含数据进行操作的方法,称为对象. ...

  4. 【CF MEMSQL 3.0 C. Pie Rules】

    time limit per test 2 seconds memory limit per test 256 megabytes input standard input output standa ...

  5. [hdu 3949]线性基+高斯消元

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3949 一开始给做出来的线性基wa了很久,最后加了一步高斯消元就过了. 之所以可以这样做,证明如下. 首 ...

  6. js中的Map对象的简单示例

    es6提供一个对象Map, 其功能类似于java中的Map, 下面是java中的Map和js中的Map的简单对比: js中的Map.set()相当于java中的Map.put(), js中的Map.s ...

  7. spring 中的@Import注解和@ImportResource注解

    概述:@Import注解是引入带有@Configuration的java类. @ImportResource是引入spring配置文件.xml 案例的核心代码如下: package com.timo. ...

  8. php SPL四种常用的数据结构

    1.栈[先进后出] $stack = new SplStack(); $stack->push('data1'); $stack->push('data2'); $stack->pu ...

  9. Nginx的client_header_buffer_size和large_client_header_buffers学习

    之前看到有人写的一篇关于nginx配置中large_client_header_buffers的问题排查的文章,其中提到: large_client_header_buffers 虽然也可以在serv ...

  10. codechef T3 计算器

    CALC: 计算器题目描述 大厨有一个计算器,计算器上有两个屏幕和两个按钮.初始时每个屏幕上显示的都是 0.没按 一次第一个按钮,就会让第一个屏幕上显示的数字加 1,同时消耗 1 单位的能量. 每按一 ...