0/1背包

给出n个物品,每个物品有Vi的价值和Wi的费用,我们总共有m块钱,求最多能得到多少价值的物品。

N<=10^3,m<=10^3

记录方案数?记录输出方案?

输出方案:

对每个dp[i][j]记录是由哪个状态转移过来的,然后从最后一直往前找,输出;

最优策略方案数:再定义一个数组f[i][j]=dp[i-1][j]>dp[i-1][j-w[i]]+v[i]?f[i-1][j]:f[i-1][j-w[i]];

if(dp[i-1][j]==dp[i-1][j-w[i]]+v[i]) f[i][j]= f[i-1][j]+f[i-1][j-w[i]];

完全背包

每一个物品可以选无限个。

dp[i][j]=max{dp[i][j-w[i]],dp[i-1][j]}

多重背包:

对每一个物品,最多能用t[i]次。

最暴力的方法就是转移的时候枚举这个物品选几个即可。

dp[i][j] = max{ dp[i-1][j-w[i]*k] + v[i]*k | k<=t[i]}

复杂度O( N*M*t[i] )

优化!

1.二进制拆分

可以把t[i]拆成1+2+4+8…2^k+x, 这样k+1组, x小于2^(k+1) ,然后我们会发现这些组能拼成0…t[i]每一种情况,然后这样我们就成了n*log(t[i])个物品的0/1背包问题。

复杂度O(n*log(t[i])*m)

2.单调队列优化:

不会

dp[i][j]=dp[i-1][j-w[i]*k]+v[i]*k k<=t[i];

fr[i][j]=dp[i-1][j*w[i]+r];

fr[i][j]=max{fr[i-1][j-k]+v[i]*k|0<=k<=t[i]};

fr[i][j]=max{fr[i-1][p]+v[i]*(j-p)|p>=j-t[i]};

fr[i][j]=max{fr[i-1][p]-v[i]*p|p>=j-t[i]}+v[i]*j;

然后对于j增加1,p的取值上届下届同时增大了1,也就像滑动窗口。

(但还是不会写)

单调队列均摊是O(m)

总复杂度就是O(n*m)的了。

分组背包:

一共有n组,每组有size[i]个物品,第i组第j个物品的费用为w[i][j],价值v[i][j],每个组里的物品是互斥的,意味着你在一组物品中只能选择一个物品,求花费小于等于m能得到的最大价值。

二维背包

给出n个化学反应,每个反应消耗a[i]升氧气和b[i]升氢气,可以得到w[i]的价值,现在总共有X升氧气和Y升氢气,求我们最多可以得到多少价值。

此外还有二维背包问题,实质上和本身和普通背包毫无思维上的区别。

因为限制条件多了一个,所以我们需要给最初最基本的dp多加一维状态。

设dp[i][x][y]表示前i个物品,消耗了x的氧气和y的氢气所能得到的最大收

益是多少。

然后考虑一个物品选还是不选即可。

对于一般背包问题:

做背包问题最关键的就是找清楚并反问自己?

这题里面 什么是容量? 什么是物品? 什么是物品的费用? 什么是

物品的价值?

容量,就是这题当中我们怎样表示状态的数组。

费用,就是用来f[i]---->f[i+v[k]],状态转移的跨度。

价值,就是你这个dp的数组,所维护的东西。维护的数值!

背包dp一定要理解好这三点,因为很多时候题目中的“费用”并非背包dp中的“费用”.

例题:vijos1240

1.给你一些房间,告诉你这些房间的容纳人数和价格。

2.安排一定数量的人住到旅馆里,满足:

a.不同性别的人如果不是夫妻那么不能住一个房间。

b.一对夫妻如果住在一起,那么房间不能安排其他的人进去哪怕房间

没盛满人。

你来写一个程序帮助佳佳找到安排这些来参加旅行的人住进旅馆所需要

的最小花费。

M:参加旅行的男性人数、 f:参加旅行的女性人数、 r:旅馆的房间数、

c:这些男女中有多少对夫妻、 Bi:每个房子容纳人数和、 Pi:每个房子

价格。注意每一个人不是单身就是和他/她唯一的妻子/丈夫一起参加旅行。

0<=m,f,r<=300, 0<=c<=Min(m,f), 0<=Pi<=10。 2<=Bi<=300

SOLUTION:

一个残忍的事实,没有夫妻可以住在一起或者只有一对夫妻住在一起;

f[i,j,k,0]表示前i个房间住j名男性k名女性并且没有夫妇住在一起的最小花费

f[i,j,k,1]表示前i个房间住j名男性k名女性并且有一对夫妇住在一起的最小花费

f[i,j,k,0]=min(f[i-1,j,k,0],f[i-1,j-v[i],k,0]+p[i],f[i-1,j,k-v[i],0]+p[i])

f[i,j,k,1]=min(f[i-1,j,k,1],f[i-1,j-v[i],k,1]+p[i],f[i-1,j,k-v[i],1]+p[i],f[i-1,j-1,k-1,0]+p[i]);

然后要注意,在写代码时f[i-1,j-1,k-1,0]+p[i]需要先保证c>=1,j-1,k-1>=0,v[i]>=2;

其余涉及-v[i]的,都要将其值与0取max(因为当你人<0了,显然所有人就都住下了,这时候也算是i个房间j个男人k个女人的一种方案,因此要取max(0,*-v[i]);

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cstdlib> using namespace std; inline int read(){
int ans=;
char last=' ',ch=getchar();
while(ch>''||ch<'') last=ch,ch=getchar();
while(ch>=''&&ch<='') ans=(ans<<)+(ans<<)+ch-'',ch=getchar();
if(last=='-') ans=-ans;
return ans;
} int m,ff,r,c,ans;
int v[],p[];
int f[][][][]; int main(){
m=read();ff=read();
r=read();c=read();
for(int i=;i<=r;i++){
v[i]=read();
p[i]=read();
}
memset(f,0x3f,sizeof(f));
f[][][][]=;
f[][][][]=;
for(int i=;i<=r;i++){
for(int j=;j<=m;j++){
for(int k=;k<=ff;k++){
f[i][j][k][]=f[i-][j][k][];
f[i][j][k][]=f[i-][j][k][];
f[i][j][k][]=min(f[i][j][k][],f[i-][max(,j-v[i])][k][]+p[i]);
f[i][j][k][]=min(f[i][j][k][],f[i-][j][max(,k-v[i])][]+p[i]); f[i][j][k][]=min(f[i][j][k][],f[i-][max(,j-v[i])][k][]+p[i]);
f[i][j][k][]=min(f[i][j][k][],f[i-][j][max(,k-v[i])][]+p[i]);
if(j->=&&k->=&&c>=&&v[i]>=) f[i][j][k][]=min(f[i][j][k][],f[i-][j-][k-][]+p[i]);
}
}
}
if(c == ) ans = f[r][m][ff][];
else ans=min(f[r][m][ff][],f[r][m][ff][]);
if(ans == 0x3f3f3f3f) printf("Impossible\n");
else printf("%d",ans);
return ;
}

一类牛逼的套路题

Bzoj 1190

给你N颗宝石,每颗宝石都有重量和价值V。要你从这些宝石中选取一些

宝石,保证总重量不超过W,且总价值最大为,并输出最大的总价值,每

颗宝石的重量符合a*2^b。

V<=1e9

a<=10; b<=30

按照b从大到小排序,先处理b大的,再处理b小的;

把总重量W表示为一个二进制数M,对应f[i][j]每一位

从高到低,定义f[i][j]表示(从b最大的到b最小的)前i个物品,剩下j*2^i的重量,最大价值是多少;

然后当我们选择某个物品时,转移有两种:1.b=i的物品还有,那么转移到f[i][j-ai]=f[i][j]+vi;

2.没有了,那么我们需要向下一位转移。剩余重量从原来的j*2^i=>k*2^(i-1),为保证剩余重量不变,我们需要让k=j*2

然后不知道为什么,还要加上我们上面总重量二进制位的0/1才行?;

bzoj3163 heoi2013 新背包问题

N个物品,第i个物品有c[i]个,购买第i个物品需要a[i]元,可获利b[i]的价

值。有m个询问,每次询问:如果第x个物品禁止购买,你有y元的话,能

获得的最大价值是多少?询问之间互相独立。

N<=1000,m<=3*10^5。

初始一空背包;

dd(l,r) 记录的是除去[l,r]外的物品的构成的背包数组。

初始调用dd(1,n);

然后dd(l,mid)时,把[mid+1,r]内的物品加入dp数组(O(n*数量));

我们这里定义的加入这个物品u,就是多考虑上这个物品之后构成的dp数组。

若是0/1背包的加入也就是做以下这个操作。

For (int i=n;i>=w[u];i--) dp[i]=max(dp[i],dp[i-w[u]]+v[u]);

当l=r时,将对应所有的询问在dp数组查询即可。

单调队列优化的话,复杂度O(n*m*log(n)),每个物品被加进去log次,每次O(m)

code:

Insert(dp,i):是在dp数组当中加入i号物品

bzoj2287

ftiasch 有 N 个物品, 体积分别是 W1, W2, ..., WN。 由于她的疏忽, 第 i 个物品丢失了。 “要使用剩下的 N - 1 物品装满容积为 x 的背包,有几种方法呢?” -- 这是经典的问题了。

她把答案记为 Count(i, x) ,想要得到所有1 <= i <= N, 1 <= x <= M的 Count(i,x) 表格。

N,M<=3000

设f[x]表示全部物品都可用恰好装满x体积时的方案数,可以用01背包算法求出。这是总方案数。

然后考虑不选某物品的情况。

设g[x]为不选当前物品恰好装满x体积时的方案数。

当x小于w[i]时, i物品一定不会被选上 g[i]=f[i]。

当x大于等于w[i]时, i物品可能会被选上,直接求不选的情况比较困难。

总方案数及f[x],不选的方案数可以想为先不选i再最后把i选上,即g[x-w[i]]。

解释:因为f[x]的结果有两种可能,一种是不选择第i个物品,那么对应的g就是g[x];

而如果选择了第i个物品,那么我们可以知道,当前物品i不被选恰好装满x-w[i]的体积的方案数是g[x-w[i]],然后因为最后确定了装第i个物品,所以只有一种方案,也就是1*g[x-w[i]];

所以g[x]=f[x]-g[x-w[i]], x从小到大枚举计算g即可。

每次都是线性复杂度,一共n次计算,总复杂度是O(n*m)

可行性的背包问题:

◦给出n个物品,每个物品有体积v[i],要求把物品分成两堆,然后使得两堆物品体积的绝对值最小。n,v[i]<=100

◦我们设总体积为sum,那么我们必定会存在一堆体积和是小于等于sum/2的,然后就是要求去选出一些物品总体积小于等于sum/2,最大能取到的体积是多少。

◦这就是经典的背包问题了。

一类整数划分问题:

1:求把n划分成k个正整数的方案数?

暴力dp:

设dp[i][j][sum]前i个数,选了j个数,和为sum的方案数是多少,答案就是dp[n][k][n],考虑这一个数选几个来转移即可。这个状态是n*k*n的转移O(sum/i)。均摊O(n*k*n*log(n))复杂度有些高。

本质是个完全背包的,那种写法的话可以做到O(n*k*n)。

神仙dp:

dp[i][j]表示把i划分成j个数的方案数;

dp[i][j]=dp[i-j][j]+dp[i-1][j-1];

dp[i-j][j]:没有1,我们可以把最下一层消掉;

dp[i-1][j-1],有1,把1搞掉

2:求把n划分成互不相同k个正整数的方案数?

暴力dp:

大同小异。

暴力dp:设dp[i][j][sum]前i个数,选了j个数,和为sum的方案数是多少,答

案就是dp[n][k][n],考虑下一个数选不选来转移即可。

本质是个0/1背包, 复杂度O(n*k*n)

神仙dp:

设dp[i][j]表示把i划分成j个数的方案数。

dp[i][j]=dp[i-j][j]+dp[i-j][j-1]

这里的有1的方案与上一题不同这里第一维是[i-j],因为要限制没有相同的数字。

保证不会互不相同;O(n√n)

3:求把n划分成k个不大于m的互不相同正整数的方案数?

dp[i][j]=dp[i-j][j]+dp[i-j][j-1]-dp[i-(m+1)][j-1];

对于可能超过m的情况,显然我们可以只看不超过m的那一部分的方案数,因为一层一层的加,所以只会更新到m+1,因此不超过那一部分的方案数为dp[i-(m+1)][j-1],这样将不合法部分减去就是合法答案,然后注意可能会有负数情况哦!

4:求把n划分成k个奇数的方案数?

………………………………………………

BZOJ 3612

给定一个杠杆,等距均匀分布一共2n+1个等重质点,支点在n+1处,求拿走k个质点后使杠杆仍然保持平衡的方案数 mod p的值。

1 <= n <= 10000, 1 <= k <= 10, 2 <= p <= 10000,且 k <= 2n+1

其实就是-n~n中求选k个不同的数,和为0的方案数。

显然求出来f[i][j]表示选出j个数和为i的方案数,然后枚举其中一端拿走几个a,以及拿走的数的重量之和x,把f[x][a]*f[x][k-a]累加之和就是最后的答案了。

这里j个数是互不相同的,也就转化成了我们的“把n划分成互不相同k个正整数的方案数”

算f的复杂度和统计答案的复杂度均是O(n*k*k)。

可重复数字纯奇纯偶划分

◦ g[i][j]:将i划分为j个偶数

◦ f[i][j]:将i划分为j个奇数

g[i][j] = f[i - j][j]; f[i][j] = f[i - 1][j - 1] + g[i - j][j];

◦不可重复也是一样的。

背包dp相关的更多相关文章

  1. 背包dp整理

    01背包 动态规划是一种高效的算法.在数学和计算机科学中,是一种将复杂问题的分成多个简单的小问题思想 ---- 分而治之.因此我们使用动态规划的时候,原问题必须是重叠的子问题.运用动态规划设计的算法比 ...

  2. hdu 5534 Partial Tree 背包DP

    Partial Tree Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://acm.hdu.edu.cn/showproblem.php?pid= ...

  3. HDU 5501 The Highest Mark 背包dp

    The Highest Mark Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://acm.hdu.edu.cn/showproblem.php?p ...

  4. Codeforces Codeforces Round #319 (Div. 2) B. Modulo Sum 背包dp

    B. Modulo Sum Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/contest/577/problem/ ...

  5. noj [1479] How many (01背包||DP||DFS)

    http://ac.nbutoj.com/Problem/view.xhtml?id=1479 [1479] How many 时间限制: 1000 ms 内存限制: 65535 K 问题描述 The ...

  6. HDU 1011 树形背包(DP) Starship Troopers

    题目链接:  HDU 1011 树形背包(DP) Starship Troopers 题意:  地图中有一些房间, 每个房间有一定的bugs和得到brains的可能性值, 一个人带领m支军队从入口(房 ...

  7. BZOJ 1004: [HNOI2008]Cards( 置换群 + burnside引理 + 背包dp + 乘法逆元 )

    题意保证了是一个置换群. 根据burnside引理, 答案为Σc(f) / (M+1). c(f)表示置换f的不动点数, 而题目限制了颜色的数量, 所以还得满足题目, 用背包dp来计算.dp(x,i, ...

  8. G - Surf Gym - 100819S -逆向背包DP

    G - Surf Gym - 100819S 思路 :有点类似 逆向背包DP , 因为这些事件发生后是对后面的时间有影响. 所以,我们 进行逆向DP,具体 见代码实现. #include<bit ...

  9. 树形DP和状压DP和背包DP

    树形DP和状压DP和背包DP 树形\(DP\)和状压\(DP\)虽然在\(NOIp\)中考的不多,但是仍然是一个比较常用的算法,因此学好这两个\(DP\)也是很重要的.而背包\(DP\)虽然以前考的次 ...

随机推荐

  1. ORACLE中的TOP-N查询(TOP-N分析)、分页查询

    TOP-N查询(TOP-N分析):就是获取某一数据集合中的前N条记录,实际应用中经常用到. Oracle中不支持SELECT TOP语句(MySQL中也没用此语句),需要借助ROWNUM伪列来实现TO ...

  2. 【NOIP2016提高A组模拟8.19】(雅礼联考day2)总结

    第一题又有gcd,又有xor,本来想直接弃疗,不过后来想到了个水法: 当两个相邻的数满足条件时,那么他们的倍数也可能满足条件.然后没打,只打了个暴力. 正解就是各种结论,各种定理搞搞. 第二题,想都不 ...

  3. bing 精美壁纸获取方式

    右键检查 打开就行了

  4. sh_05_函数的参数

    sh_05_函数的参数 def sum_2_num(num1, num2): """对两个数字的求和""" # num1 = 10 # nu ...

  5. Windows和Linux下搭建J2sdk的环境

    J2SDK 作为jsp系统配置中必不可少的组件,越来越多的得到应用.下来是我整理的以往工作时搜集的资料.使用时方便查询,希望对广大的工程师有帮助. windows服务器环境下 j2sdk 的安装和环境 ...

  6. 3D Computer Grapihcs Using OpenGL - 19 Vertex Array Object(顶点数组对象)

    大部分OpenGL教程都会在一开始就讲解VAO,但是该教程的作者认为这是很不合理的,因为要理解它的作用需要建立在我们此前学过的知识基础上.因此直到教程已经进行了一大半,作者才引入VAO这个概念.在我看 ...

  7. DVWA--XSS(DOM)

    0X01爱之先了解 DOM,全称Document Object Model,是一个平台和语言都中立的接口,可以使程序和脚本能够动态访问和更新文档的内容.结构以及样式. DOM型XSS其实是一种特殊类型 ...

  8. 【Django】搭建Django administration并登录

    Python自带一个后台管理系统,这个后台管理系统搭建与登陆呢? 新建项目Django_Admin 文件结构目录如下: 创建APP 在pycharm下方的terminal终端中输入命令: python ...

  9. 火狐firefox进行post提交测试

    1,打开火狐浏览器,将测试url复制到地址栏.按F12,进行连接. 2,点击连接:再点击“编辑与重发” 3,请求头中加入如下一行: Content-Type: application/json; ch ...

  10. serlvet操作数据库

    工具:eclipse 数据库工具:mysql java ee操作数据库,首先要导入数据库驱动文件,我用的是mysql 刚开始,很多人代码正确但是就是连接不上,原因就是忘了驱动文件的导入. 我的驱动文件 ...