随笔分类 - DP
摘要:题意: 有n 个砖块,有不同的长宽高,分为三种类型,要求是: When di = 0 the block's length and width must be more or equal to the block's length and width which lies under the block. When di = 1 the block's length and width must be more or equal to the block's length which lies under the block and width and the
阅读全文
摘要:题意:A password locker with N digits, each digit can be rotated to 0-9 circularly. You can rotate 1-3 consecutive digits up or down in one step. For examples: 567890 -> 567901 (by rotating the last 3 digits up) 000000 -> 000900 (by rotating the 4th digit down) Given the current state and the sec
阅读全文
摘要:题意: 在连续的 n 秒中,每秒会出现 m 个龙珠,出现之后会立即消失,知道了第一秒所在的位置,每从一个位置移动到另一个位置的时候,消耗的价值为 abs(i-j), 知道了次出现的龙珠的价值,问 n 秒之后得到的最大价值是多少。分析: 当 pos[i][j] >= pos[i-1][k] 时:dp[i][j]= min( dp[i-1][k] - pos[i-1][k] ) + pos[i][j] + w[i][j]; 当 pos[i][j] <= pos[i-1][k] 时:dp[i][j]= min( dp[i-1][k] + pos[i-1][k] ) - pos[i][j]
阅读全文
摘要:题意: 有 n 个团队和 m 艘船,每艘船的载客量为 k,每个团队的人数为ai+1 ,转载该团队可获利润 bi,要求每个团队的所有人必须在同一艘船上, 且团队优先级高的团队所在船编号不能大于优先级低的团队,求可以获得的最大利润。分析:dp[i] 表示获得 i 利润时需要的最少船位,且要保证优先级高的团队优先考虑。#include <stdio.h>#include <string.h>#define INF 0x1f1f1f1f#define v 10005int min(int a,int b){ return a<b?a:b;}int dp[v+1];int
阅读全文
摘要:题意: 有 n 个砖块,知道了每个砖块的位置和人的起始位置 st,现在要把这 n 块砖搬到st,每次最多能搬回两块砖,搬砖块的体力耗费为两个地点距离的平方, 问搬回这 n 块砖所需消耗的最小体力是多少,并按字典序输出搬砖块的顺序。分析: dp[i] 表示 i 状态的最小值 dp[i] = max(dp[i],dp[i |(1<<j)]+2*dis[n][j]) 搬一块砖的时候 dp[i] = max(dp[i],dp[i|(1<<j)|(1<<k)]+dis[n][j]+dis[j][k]+dis[n][k]) 搬两块砖的时候 同时用pre[] 记录状态转移
阅读全文
摘要:题意: 用正方形拍子拍蚊子,拍T次,每次至少要拍死一个蚊子,一次拍死N只得N*N点经验,每次每只蚊子的位置不一样,死了的蚊子不记入以后,问最多能得 多少经验。分析: dp[i][j] 表示第 i 次在 j 状态下的最大经验值,需要求出第 i 次能一次拍死的所有的蚊子组合,对于每只蚊子需要考虑两种情况: ① 刚好被覆盖的情况 ② 刚好不被覆盖的情况 可以在原来的坐标加上一个很小的偏移量#include<stdio.h>#include<string.h>#include<algorithm>#include<vector>using namespa
阅读全文
摘要:题意: 有n 个人走在一条路上,其中一些人可能是一个组的,每个人都说出了自己所在组前方的人数和后方的人数,问最多有多少人说的是真话。分析: dp[i][j] 表示从第 i +1 个人到第 j 个人为一组时的最优值 t[i][j] 表示描述中从第 i +1 个人到第 j 个人为一组的数量 注意的是: t[i][j]的值不可能超过 n-(j-i+1) s[i]保存以第 i 个人为结尾的最优值 转移方程: dp[i][j]=s[i]+t[i][j] s[j] = max (s[j],dp[i][j])#include<stdio.h>#include<string.h>#de
阅读全文
摘要:题意:已知有 2*n个敌人,用枪射击n 次,每次消灭2个敌人,消耗的能量为自己所在位置到第一个敌人的距离加上第一个敌人到第二个敌人的距离,问消灭 所有敌人所需要消耗的最少能量是多少。分析:状态DP: 由于每两个敌人消灭的时间不影响答案,所以只需要一维的DP保存所有可能的组合状态即可 转移方程:dp[i] = min (dp[i], dp[i+(1<<i)+(1<<j)]+dis)#include<stdio.h>#include<string.h>#include<math.h>#define clr(x)memset(x,0,siz
阅读全文
摘要:题意: 有 n 个物品,每个物品都有一定的价值和花费,而且买的时候自己的钱不能低于那个物品的指标,问最后可以买到的物品的最大价值是多少。分析: 需要对物品按 qi-pi 的值从小到大排序,因为这样可以保证每次更新的状态值从小到大递增,前面更新过的状态不会影响后面更新的状态。#include<stdio.h>#include<string.h>#include<algorithm>#define clr(x)memset(x,0,sizeof(x))#define max(a,b)(a)>(b)?(a):(b)using namespace std;st
阅读全文
摘要:题意: 有 n 个货物,并且知道了每个货物的重量,每次用载重量分别为c1,c2的火车装载,问最少需要运送多少次可以将货物运完。分析: 找出所有状态(1.....(1<<n)-1)中选出可以用两辆车一次运完的状态 把每个状态都看作一个物品,重量为该状态的总重量,价值为 1求解 01 背包,dp[(1<<n)-1]为最优解 转移方程: dp[stat|j]=min(dp[stat|j],dp[j]+1) 注意 stat 和 j 不能有交集#include<stdio.h>#include<string.h>#define clr(x)memset(x
阅读全文
摘要:题意: Alice 和 Bob在一颗树上轮流走,知道了每条边的长度,Alice想走的权值和尽量小,Bob想走尽量大,同时所走的权值和必须在[L, R]这个给定的区间内, Bob先走,问Bob 能得走的最大的权值和是多少? 如果还能走,Alice就不能停下来。分析: dp[r] 表示到节点 r 的最优值,从叶子递归,Alice选每次最小走,Bob选最大走,d[u]表示从跟到节点u的距离, d[u]+dp[t]+cost(u, t) 必须在[L, R]之间才转移#include<stdio.h>#include<string.h>#define INF 0x1f1f1f1f
阅读全文
摘要:题意: 一个有 N 个节点的树形的地图,知道了每条变经过所需要的时间,现在给出时间T,问能不能在T时间内从 1号节点到 N 节点。每个节点都有相对应的价值,而且每个价值只能被取一次,问如果可以从1 号节点走到 n 号 节点的话,最多可以取到的最大价值为多少。分析:先求出从 1 号节点到 n 号节点的最短路,如果花费大于时间 T,则直接输出不符合, 将最短路上的权值全部赋值为 0, 在总时间 T 上减去 最短路的长度,表示最短路已经走过,对其它点进行树形背包求解, 需要注意的是如果不是最短路上的边都要走两次,即走过去还要再走回来, 状态转移方程: dp[i][j]=max(dp[i][j],dp
阅读全文
摘要:题意: 有N 个点的无向图,要去其中 h个地点做事,做事需要先办理护照,之后可以挣一定数量的钱,知道了一开始有的总钱数,和 一些城市之间道路的花费,问可不可以在 指定的 h 个城市打完工,并回到起点 1.分析: 状态DP,直接枚举所有可能状态即可。#include<stdio.h>#include<string.h>#define max(a,b)(a)>(b)?(a):(b)#define INF 0x3f3f3f3fint g[155][155];int dp[1<<16][16];int num[22];int earn[22];int cost
阅读全文
摘要:题意: 求出包含样例所有子串的字符串的最小长度。分析: dp[i][j]表示在 i 状态下 ,以第 j 个字符串结尾的最优值。#include<stdio.h>#include<string.h>#define INF 0x1f1f1f1f#define clr(x)memset(x,0,sizeof(x))int min(int a,int b){ return a<b?a:b;}int dp[1<<16][16];int g[16][16];int add_s(char *s1,char *s2) // 求出 s2 串加在s1 串后增加的长度{ i
阅读全文
摘要:题意:知道了每个时间段的休息可以获得能量,和连续休息可以获得的能量。求在能休息慢m 分钟,且最长连续时间段不超过 r 所能获得的最大能量值。分析:dp[i][j][k] 表示到第 i 分钟休息了j 分钟,连续睡了k 分钟获得最大值。#include<stdio.h>#include<string.h>#define max(a,b)(a)>(b)?(a):(b)#define clr(x)memset(x,0,sizeof(x))int dp[505][55][55];int a[505];int main(){ int t,i,j,k,n,m,r; scanf(
阅读全文
摘要:题意: 给两个数组,求最长公共递增子序列。分析: dp[i,j]表示a串前i个字符,b串前j个字符组成的,并且以b[j]为结尾的最长的LCIS,转移方程: dp[i,j]=dp[i-1,j]; //a[i]与b[j]不等 dp[i,j]=dp[i-1,k]+1; (1<=k<=j-1) //a[i]与b[j] 相等 以上转移方程是O(n^3)时间复杂度 优化: 由于最外层循环是 i,第二层是 j,循环 j 的时候,实际上同时找出dp[i-1,k] 的最大值MAX 方法:循环 j 的同时,若a[i]>b[j],更新MAX (因为当且仅当a[i]>b[j]时,后边循环 j
阅读全文
摘要:题意: 有 n 个人,他们之间的关系有四种,给出一些关系 a,b 表示b 知道 a,现在想把这些人分成两组,每个组里面所有人都相互知道,如果可以分成这两组, 找出两组人数相差最少的情况。分析:如果 a 和 b 不是相互知道,就在a,b之间连一条双向边,表示a 和b 绝不能分在一个组里 建好图之后,进行染色,判断是否是二分图,如果不是二分图,肯定不存在符合条件的情况 染色的同时,记录每个连通块中每个部分的个数,并记录路径 用 01 背包标记所有存在的状态,找到差值最小的情况#include<stdio.h>#include<string.h>#define clr(x)m
阅读全文
摘要:题意: 给出n 个数,每个数的范围在1..k之间,问最短非子序列的长度是多少。分析:将集合尽可能划分成多个区间,并满足每个区间包含1..k之间所有的数,如果分成了 x 个区间,那么这些区间一定包含了所有长度为 x 的子序列,而没有包含全 部的长度为 x+1 的子序列,因为可以通过在每个区间任取一个数来组成长度为 x 的序列。#include<stdio.h>#include<string.h>#define clr(x)memset(x,0,sizeof(x))int v[10005];int main(){ int n,k,p,i,res,num; while(sca
阅读全文
摘要:题意: 对于从1到N (1 <= N <= 39) 的连续整数集合,能划分成两个子集合,且保证每个集合的数字和是相等的。举个例子,如果N=3, 对于{1,2,3}能划分成两个子集合,每个子集合的所有数字和是相等的:{3} 和 {1,2} 给出一个 N 值,问最多能划分成多少种等值的集合。分析:每个数字只用到一次,每种情况的存在数可以由之前的存在的数来递推得到,01背包的变形。#include<stdio.h>#include<string.h>#define clr(x)memset(x,0,sizeof(x))long long f[50000];int
阅读全文
摘要:题意:为了降低出现暴动及逃跑事件的风险,两个相同容量的临近监狱的管理层决定重新安排他们的囚犯。他们想用一个监狱里一半的囚犯去交换另一个监狱里一半的囚犯 然而,从囚犯们犯罪史的存档信息可知某些囚犯成对被关在同一座监狱里时会很危险,这也是现今他们被分开的原因,即对于每对这样的囚犯,一名在第一个监狱服 刑,另一名在第二座监狱服刑。管理层认同将那些囚犯保持分开的重要性,但这也使得他们的新安排任务有些棘手,事实上,他们很快就了解到有时这个互换一半囚 犯的意愿是不可能达成的。每当这种情况下,他们不得不满足于交换尽可能接近一半数量的囚犯。分析:需要把第一座监狱和第二所监狱有联系的放到一起,形成一个连通块,即
阅读全文