背包问题【DP】
- 有一个背包,背包容量是M=150kg。有7个物品,物品不可以分割成任意大小。要求尽可能让装入背包中的物品总价值最大,但不能超过总容量。
01背包
f[j]=max(f[j],f[j-w[i]]+c[i]);
搬书【DP】
- 陈老师桌上的书有三堆,每一堆都有厚厚的一叠,你想逗一下陈老师,于是你设计一个最累的方式给他,让他把书拿下来给同学们。若告诉你这三堆分别有i,j,k本书,以及每堆从下到上书的质量,每次取书只能从任一堆的最上面取,显然,每次取书陈老师的体力消耗都会加大,这里用体力系数代表,取下第一本书时,体力系数为1,第二本书时体力系数为2,依次类推,而每次体力消耗值则为体力系数与书的重量之积。
n^3枚举从哪一堆上选
f[a][b][c] = max(f[a-1][b][c]+w[1][a]*T,f[a][b-1][c]+w[2][b]*T,f[a][b][c-1]+w[3][c]*T);
排队问题(贪心策略明显)【反证法】
- 在一个医院B超室,有n个人要做不同身体部位的B超,已知每个人需要处理的时间为t[i](1≤i≤n),请求出一种排列次序,使每个人排队等候时间总和最小。
按时间从小到大排。
证明:若t[i]>t[j],交换i,j一定能得到更优的解
神牛果(贪心策略明显)【反证法】
- 在某次膜拜大会上,n个神牛被要求集体膜拜。这些神牛被奖励每人吃一些神牛果。但是,每个神牛的肚量不一样。为了不显得某些人吃得太多,决定两人一组,使得吃得最多的那组吃得尽量少。
排序,每次取出最大和最小的为一组。
修理牛棚(贪心策略明显)【倒推法】
- John的牛棚一个紧挨着另一个排成一行,有些牛棚里有牛,有些没有,所有的牛棚有相同的宽度。 自门遗失以后,农民John必须尽快在牛棚前面竖立起新的木板。 他的新木材供应商将会供应他任何他想要的长度,但是供应商只能提供有限数目的木板。农民John想将他购买的木板总长度减到最少。
- 给出能买到的木板最大的数目M,牛棚的总数S(1≤S≤200),牛棚里牛的总数C(1≤C≤S),和牛所在的牛棚的编号X(1≤X≤S)。输出所需木板的最小总长度作为答案。
初始为一整块木板,可以选择m-1个断点。
将断开的长度从大到小排。
删数(贪心策略明显)【倒推法】
- 给定n(n≤100)位正整数a,去掉其中任意k≤n个数字后,剩下的数字按原次序排列组成一个新的正整数。对于给定的n位正整数a和正整数k,设计一个算法找出剩下数字组成的新数最小的删数方案。
因为一共选n-k个数,设当前为第i个,上次选了第L个
至少要留n-k-i个给后面,那么第i个即为min(a[L+1]~a[n-k-i+1])
(或者:从高位到低位遍历k次,如果数字递增则删最大的(最后一位);
否则删开始递减的第一个(左边第一个递减区间的第一位),比如123654798,就删掉6 )
调整法:列出不等式,交换等式两边得到贪心方案
奶酪工厂(贪心策略不明显)【调整法】
- 接下来的N(1≤N≤10000)星期中,奶酪工厂在第i个星期要花C_i分来生产一个单位的奶酪。约克奶酪工厂拥有一个无限大的仓库,每个星期生产的多余的奶酪都会放在这里。而且每个星期存放一个单位的奶酪要花费S分。
- 工厂最近收到了客戶N个星期的订单,第i个星期要向客戶提供Y_i 个单位的奶酪。当然这些奶酪可以在第i个星期时生产,也可以从仓库中拿取。采用怎样的生产策略约克奶酪工厂的花费最小呢?
某周需要的奶酪一定在同一周生产,也就是说与奶酪订单需要量无关。
问题可以转化为当前周生产奶酪的最低价格。
设i<j<k,如果c[i]+(j-i)*s < c[j],则:
c[i]+(j-i)*s+(k-j)*s < c[j]+(k-j)*s
c[i]+(k-i)*s < c[j]+(k-j)*s
设第i周的最优生产时间为f[i],则一定有f[i] = f[i-1]或i
每次比较并记录当前周的生产时间即可。
堆积木【调整法】
- 现在有N块积木,每块积木都有自重W和正常状态下的承重能力F,现在要把这N块积木垒在一起,但是有可能某块积木的负重超过了它在正常状态下的承重能力,那么这块积木就有被压坏的危险,请问应该如何堆这N块积木使得N块积木中最大的压力指数最小。这里定义压力指数为该积木的负重与其在正常状态下的承重能力的差值。
- 1≤N≤50000,1≤W≤10000,1≤F≤10^9。
没想出来
设当前最优的方案从下到上积木编号为1,2
则有f[1]-w[2] < f[2]-w[1]
f[1]+w[2] < f[2]+w[1]
即从下到上的顺序是按f+w从小到大排。
国王游戏【调整法】
- 国王邀请n位大臣来玩一个有奖游戏。首先,他让每个大臣在左、右手上面分别写下一个整数,国王自己也在左、右手上各写一个整数。然后,让这n位大臣排成一排,国王始终站在队伍的最前面。排好队后,所有的大臣都会获得国王奖赏的若干金币,每位大臣获得的金币数分别是:排在该大臣前面的所有人的左手上的数的乘积除以他自己右手上的数,然后向下取整得到的结果。
- 国王想请你帮他重新安排一下队伍的顺序,使得获得奖赏最多的大臣,所获奖赏尽可能的少。
设当前最优的方案从前到后编号为0,1,2(0为国王)
则max(a[0]/b[1],a[0]*a[1]/b[2]) < max(a[0]/b[2],a[0]*a[2]/b[1])
因为一定有a[0]*a[2]/b[1] > a[0]/b[1],a[0]*a[1]/b[2] > a[0]/b[2]
所以转化为 a[0]*a[1]/b[2] < a[0]*a[2]/b[1]
a[1]*b[1] < a[2]*b[2]
即按从前往后的顺序是按a*b从小到大排。
让步法:竞争公共资源时,尽量使剩余选择最大化 我瞎编的
智力大冲浪【让步法】
- 比赛时间分为n(n≤5000)个时段,给出了很多小游戏,每个小游戏都必须在规定期限ti(1≤ti≤n)。如果一个游戏没能在规定期限前完成,则要从奖励费m元中扣去一部分钱wi,wi为自然数,不同的游戏扣去的钱是不一样的。当然每个游戏本身都很简单,保证每个参赛者都能在一个时间段内完成,而且必须从整时段开始。主持人只是想考考每个参赛者如何安排组织自己做游戏的顺序。作为参赛者,小伟很想赢得冠军,当然更想赢取最多的钱!
总钱数是一定的,问题转化为使扣去的钱最少。
按w从大到小排序。
检查1~t[i]是否有时间没有没占用,如果都被占了则要扣去w[i]的钱
如果有可选的,则尽量选择时间靠后的,给其他的留出前面的时间!
整数区间【让步法】
- 我们定义一个整数区间[a,b]:是一个从a开始至b 结束的连续整数的集合。编一个程序,对给定的 n(n≤1000 )个区间,找出满足下述条件的所含元素个数最少的集合中元素的个数:对于所给定的每一个区间,都至少有两个不同的整数属于该集合。
按右端点从小到大排序。这样右端点单调,即保证,在当前选取的整数序列a[]中,
若下一个区间不包含a[i],则一定不包含a[i-1],a[i-2]….
即最有可能被下一个区间包含的一定是最右边的数。
设当前已经选取的整数中,最右边的两个数为x,y。
检查x,y是否被当前区间包含;若都包含,则继续下一个区间;
若不包含x,包含y,则选择这个区间的右端点。
若都不包含,则选择最右的两个(右端点-1和右端点)。
这样选择出来的数是单调递增的,且尽量大,也就是被下一个区间包含的机会尽量大。
活动选择【让步法】
- 假设有一个需要使用某一资源的n(n≤1000 )个活动组成的集合S,S={1,…,n}。该资源一次只能被一个活动占有,每一个活动有一个开始时间b[i]和结束时间e[i](b[i]≤e[i])。若b[i]>e[j]或者b[j]>e[i],则活动 i 和活动 j 兼容。
- 你的任务是:选择由互相兼容的活动组成的最大集合。
上一个活动结束的越早越好。
按右端点从小到大排序,能选则选。
雷达安装【让步法】
- 假定海岸线是一条无限延伸的直线,陆地在海岸线的一边,大海在另一侧。海中有许多岛屿,每一个小岛我们可以认为是一个点。现在要在海岸线上安装雷达,雷达的覆盖范围是d,也就是说大海中一个小岛能被安装的雷达覆盖,那么它们之间的距离最大为d。
- 我们使用平面直角坐标系,定义海岸线是x轴,大海在x轴上方,陆地在下方。给你海中每一个岛屿的坐标位置(x,y)和要安装的雷达所覆盖的范围d,你的任务是写一个程序计算出至少安装多少个雷达能将所有的岛屿覆盖。
雷达的覆盖范围是一样的,
每个小岛可以被一定范围内的雷达覆盖到,可求出每个小岛可选的雷达区间。
转化为和整数区间类似的问题。
按右端点排序,设安装的雷达中最右的横坐标为x。
若x在这个小岛的区间内,则继续;否则选这个小岛的区间的右端点安装雷达。
晒衣服(贪心+桶)
- 假设衣服在自然条件下用1的单位时间可以晒干A点湿度。抠门的Smart买了1台烘衣机。使用烘衣机可以让他用1个单位时间使1件衣服除了自然晒干的A点湿度外,还可烘干B点湿度,但在1个单位时间内只能对1件衣服使用。
- N件的衣服因为种种原因而不一样湿,现在告诉你每件衣服的湿度,要你求出弄干所有衣服的最少时间(湿度为0为干)。
因为每个单位时间所有衣服自然晒干1点,所以要使每个单位时间湿度最大的衣服湿度最小
所以烘干机给当前湿度最大的用就行了。
维护一个优先队列,元素为初始湿度,每次取出队首,把它减去B点湿度,再压回去。
当队首小于A*t时,说明已全部晾干
游戏通关(贪心+并查集)
- 小明需要完成N个任务才能将这个游戏通关。
- 每个任务完成时限T,就是这个任务必须在时间T之前完成(你可以认为游戏刚开始的时间为1),还有完成这个任务小明可以获得一定的奖励W。由于小明娴熟的技术以及任务的简单,他可以在一个单位时间将任务完成。
- 小明想要在老师到来之前将任务全部完成,同时他也想获得最多的奖励。
- N≤200000,Ti≤200000,Wi≤2000
这道题和智力大冲浪相同,只是将最小减少奖励改为最大增加奖励;
奖励从大到小排序,并且在可行区间内尽量往后放。
不过数据范围较大,如果暴力枚举1~t[i]大概会超时。
用并查集优化:把已占用的时间全部连起来,fa[x]-1即为可选的;
想要选择时间x时,若x可用,分别判断x-1、x+1是否也已被占用,被占用则与x连接;
若x不可用,则上一个可用的时间即为getfa(x)-1。
探险(贪心+堆)
- 一群驴友驾驶一辆卡车前往树林里探险。但是由于他们的驾驶技术太糟,油箱在路上给弄破了,所以他们每前进一个单位的路程就会消耗掉一个单位的油(包括漏掉的汽油),为了修好油箱,驴友们必须前往最近的城市。在当前位置和城市之间有N个加油站,驴友们可以在加油站加1到100单位的油(每个加油站存油量不等)。对于人来说,树林是个危险的地方。所以,驴友们要尽可能的少停站加油。幸运的是,这辆卡车的油箱非常大,你可以认为它的容量是无穷大的。卡车在离城P个单位时还有L个单位的油。 你要算出驴友们至少要停几站才能到城市,或者驴友们根本到不了城市。
油不花钱,油箱也没有容量上限,从起点到终点需要的油是一定的。
想要加油次数尽量少,就要每次加的油尽量多。按存油量大小维护优先队列。
在起点到终点的路上,一定会经历每一个加油站。
枚举每一个加油站,如果当前的总油量能到达,则可以在这里加油,把它加入优先队列。
如果不能到达,则在能加油的加油站中加最多的,即取出优先队列的队首,加入总油量,直到总油量能到达这个加油站为止。
若优先队列为空时也到不了则无解。
优惠券(贪心+堆)【调整法】
- 新学期开学了,Smart准备买一些新书,书店有N本新书,第i本新书价格为Pi,使用优惠券购买第i本书时价格会降为Ci。Smart有K张优惠券,每本新书只能使用一次优惠券。Smart想知道花不超过M的钱最多可以买多少本新书?
要买的最多,那一定是先买优惠券价最便宜的。
如果优惠券没用完,钱就花光了,当前买的书即为答案。
如果钱还有剩,那么对于剩下的n-k本书,
判断是用原价买它,或把另一本书的优惠券给它而另一本原件买比较便宜。
但是若枚举所有已经使用优惠券的书,时间复杂度显然不友好。
交换条件为c[j]+p[i] < c[i]+p[j],即p[i]-c[i] < p[j]-c[j]
因此,优先队列要维护的是:原价和优惠券价的差值,从小到大排。
每当对某本书使用优惠券时,把它的差值压入优先队列。
探讨人生(贪心+枚举)
- Smart每次他与好友A探讨人生要花费a个小时,并可以得到x点人生经验;每次与好友B探讨人生要花费b个小时,并得到y点人生经验。但是Smart的精力是有限的,他只能抽出n个小时来跟他的友人们探讨人生,若这n个小时并没有被用完,则Smart会把剩下的时间拿来跟好友C聊天,而这并不能得到人生经验。现在Smart想知道,他最多可以得到多少点人生经验。
- n≤1e12(我随便写的)
这不是多重背包吗
贪心优化暴力…
因为只有两个人,所以暴力枚举探讨次数就可以了。
原来没给数据范围,所以我编了一个… √n可过。
剪枝:先swap一下,保证与A探讨单位时间经验更多。
为了使枚举的探讨次数控制在√n以内,需要判断一下:
若a>√n,则枚举次数一定小于√n,正常枚举与a探讨次数即可。
否则,枚举与B探讨次数。
因为与A探讨更优,即与A探讨b次优于与B探讨a次,
所以当枚举与B探讨次数大于等于a时,一定不如把其中的a次变成和A探讨。
所以最多只要枚举a次。
例题:数字游戏(贪心+DP)
- 小W发明了一个游戏,他在黑板上写出一行数字a1,a2,…an(n≤200),然后给你m个回合的机会,每个回合你可以从中选一个数擦除它,接着剩下来的每个数字ai都要递减一个值bi。如此重复m个回合,所有你擦除的数字之和就是你得到的分数。
- 编程帮小W算算,对于每个给出的an和bn序列,可以得到的最大得分是多少?
贪心得到dp枚举顺序。
当m=n,即全选时,显然按b从大到小选。
m<n时,需要用dp解决,但策略是相同的,即把b从大到小排序。
设f[j]表示选j个数得到的最大价值。
状态转移方程:f[j] = max(f[j-1]+a[i]-b[i]*(j-1))
马步距离(贪心+搜索)
- 在国际象棋和中国象棋中,马的移动规则相同,都是走“日”字,我们将这种移动方式称为马步移动。如图所示。
- 从标号为 0 的点出发,可以经过一步马步移动达到标号为 1 的点,经过两步马步移动达到标号为 2 的点。任给平面上的两点 p 和 s ,它们的坐标分别为 (xp,yp) 和 (xs,ys) ,其中,xp,yp,xs,ys 均为整数。假设棋盘充分大,并且坐标可以为负数。现在请你求出从点 p 到点 s 至少需要经过多少次马步移动?
- xp,yp,xs,ys < 10000000。
直接搜索会超时,考虑优化。
因为棋盘无限大,所以四个方向是一样的,也就是说可以任意进行对称。
为了方便,把s翻转到p的右下。
通过打表可以发现, p和s相距较远时,移动的方式只有从(x,y)到(x+1,y+2)或(x+2,y+1),
也就是一直向右下走就行了…
打出大概5,5的矩阵(不放心的话就多打点…),当距离差超出这个矩阵时,
取绝对值,令x,y>0,swap使x>y,将x-=2,y-=1。
当x,y进入矩阵时,直接返回答案即可。
不想打表的话,也可以把x,y缩小到一定范围内后进行bfs。
原文地址:https://www.cnblogs.com/mogeko/p/11762212.html