随笔分类 - 动态规划
摘要:该题说明了状态开设的意义一样,但是从哪个方向去理解推倒状态的转移对解题非常关键.该题扣住是否所有的盘子中有空盘子,就得到了一个非常简单且优美的方程.如果从当前盘子的放置状态或者是当前苹果的放置状态来求解状态转移方程就不能写出来.这和题意中的相同盘子,相同苹果有很大的关系.代码如下:#include <cstdlib>#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>using namespace std;int N, M, dp[15][
阅读全文
摘要:#include <cstring>#include <cstdio>#include <cstdlib>#include <algorithm>using namespace std;/*该题给定一个N,那么在有1.2.3...N个数字的情况下,这些数字高低交替进行排列把所有符合情况的进行一个字典序排列,问第C个排列是一个怎样的排列up[i][j]代表长度为i,第一位为j且后面需跟着一个上升数字的方案总数dn[i][j]代表长度为i,第一位为j且后面需跟着一个下降数字的方案总数根据我们所定义的状态,我们能够得到一个状态的转移关系(用来状态转移来
阅读全文
摘要:这题的状态推倒极富想象力,原来写过的代码又忘了如何去写了......题意:其实就和以前做过的一道我要长高一模一样,给定N个数字,现在要求连续的两个数字之差的绝对值乘以C最小,每个数字可以变大,变大所带来的开销为变量的平方. 状态方程为 dp[i][j] = min(dp[i-1][k] + C*|j-k| + (j-H[i]) ^ 2) if (j >= k) dp[i][j] = min(dp[i-1][k] - C*k) +C*j + (j-H[i])^2 if (j <= k) dp[i][j] = min(dp[i-1][k] + C*k) - C*j + (j-H[i])
阅读全文
摘要:http://www.cnblogs.com/Lyush/archive/2012/03/23/2413160.html曾几何时,也写过这一题,那是刚跟着做什么状态压缩dp的时候,1844MS过的,现在终于0MS了.这次的做法有点不一样,首先原来的两个指数级的for循环嵌套,变成一个指数级嵌套一个合法状态的个数,状态的含义也发生了改变,由原来的0,1只表示覆盖,变成了0表示横向覆盖,1表示了纵向覆盖,0和1保留了更多的信息,最后采用了一种退化机制来确保一列中不出现连续的奇数个1,即如果出现了偶数个1的话,那么最后这个1就等价于0,表示下一行下的这一列为0为1均可.那么上一层的合法状态由于发生退
阅读全文
摘要:题意:给定一个矩阵,每个元素代表了一个开销,每个位置只能够由上,左,右这些位置传递过来,问从第一行走到最后一行的最少代价为多少.解法:1.最短路 若是用最短路来解这一题,我们需要进行构边,同层相邻的节点连双向边,不同层从上往下连单向边,最后设定一个超级源点和超级终点即可.代码如下:#include <cstdlib>#include <cstring>#include <cstdio>#include <queue>#include <iostream>#include <algorithm>#include <ve
阅读全文
摘要:DP第二题,做过很多次了,这次没用记忆化搜索,而是先排序之后for循环进行动态规划.代码如下:#include <cstdlib>#include <cstring>#include <cstdio>#include <cmath>#include <algorithm>using namespace std;int N;struct Point { double x, y; void read() { scanf("%lf %lf", &x, &y); }}p[105];int main() {
阅读全文
摘要:详见代码:#include <cstdlib>#include <cstring>#include <cstdio>#include <algorithm>#define MAXN 100using namespace std;// 给定一个有数值的矩形,求出和最大的子矩形// 经典的DP问题/*思路:枚举所有的行,然后将这些行的列进行相加构成一个串 然后再进行一次一维空间上的DP即可 */int N, M[MAXN+5][MAXN+5], sum[MAXN+5][MAXN+5], seq[MAXN+5];int DP() { int Max =
阅读全文
摘要:这一题不是自己想出来的思路,看了一眼解题报告。题意是这样的,求给定的一棵树中是否存在一条长度为L的路径,注意这个值可能为负数,这也是简洁版的解题报告的最后一句忠告。这题有一个非常好的特性,那就是所有的边的长度要么为1,要么为2,也就是说我们所求得的路径是由若干个1,2组成的。那么也就有了下面的结论:当我们得到一条长度为S的路径时,现在考虑到构成路径S的左右两端的两条边,这两条边的组合情况是(1, 1), (1, 2), (2, 2)那么注意到我们始终可以去掉长度为2的一段,因此有结论:若整个树中最长的偶数边为EM,最长的奇数边为OM,由于任何一个询问不是奇数就是偶数,那么如果这个数是偶数的话,
阅读全文
摘要:给定一些关系,求这样的一个划分,满足以下几点:1、每个组合至少有一个成员;2、每个人只能属于一个组;2、每个组内的成员必须相互认识;3、两个组的成员个数要尽可能的接近。首先由必须两两认识我们可以将有向图转化为无向图,之后,我们如果直接对这个图求连通分量的话,有以下结论,如果连通分量的个数为2的话,那么直接可以划分了,如果超过两个的话那么肯定就是没有结果,也就是无法进行分组。最难处理的就是所有点的连通的话,那么如何去做一个划分呢,这个就和割点有关系了,分离一个割点会产生多个连通分量,这要必须保证那些多出来的要再同一个集合内,这样这个问题就很复杂了。简单的做法是建立一个反图,再对这个反图求一次连通
阅读全文
摘要:dp[i]表示第i个位置跳出去的期望天数,先构造出N+1到N+5这几个位置,然后先把dp[N-N+5]这六个位置全部赋值为0,因为这几个位置都已经出去了。然后就是递推了如果该点没有航班的话:dp[x] = (1/6)*(dp[x+1] + dp[x+2] + dp[x+3] + dp[x+4] + dp[x+5] + dp[x+6]) + 1;否则:dp[x] = dp[link[x]]; 其中link[x]表示x连到哪一个点。代码如下:#include<iostream>#include<cstdio>#include<cstdlib>#include&l
阅读全文
摘要:这题是求一个圈中取出若干相邻的数,求其中的最大值,不能够同时取所有的数。本来想着要扩张出一个圈出来,再通过限定长度来转化为线段上的问题,但是这样明显就复杂很多了,有一个结论就是当这个区间在[1-N]之间的话,那么直接输出最大值,否则一定是sum - min[1-N],也就是说如果区间跨越了1,N两个点,那么[1-N]中就一定隐藏了最小子串和。很好理解,因为整个循环串就是由一个最大子串和一个最小子串组成的。线段树的节点中要存储较多的值:lmax -- 从左边开始至少取一个节点的最大值lmin -- 从左边开始至少取一个节点的最小值rmax -- 从右边开始至少取一个节点的最大值rmin -- 从
阅读全文
摘要:题目意思很好懂,就是问最少出来多少个是的队中的每一个人都能够看到最左边或者是最右边。我们通过枚举没一点作为最高点来求解这个问题,有个要注意的地方就是最高点其实允许有两个,即一个往左看,一个往右看。所以我们就只能够去枚举到左边的最高点,通过搜索去找右边的最高点(这个最高点只要满足高度小于等于我们枚举的点即可)。代码如下:#include <iostream>#include <cstdlib>#include <cstdio>#include <cstring>#include <algorithm>#include <cmath
阅读全文
摘要:给定一个串,两个串有A,T,G,C组成,求其两两配对,可以各自插入如干个空格,求最后的和值得最大值。可以定义如下状态,f[i][j]表示1串到第i位,2串到达第j位通过各自补充空格达到一一配对的最终最大值,这就意味着f[3][0]也是有意义的,表示1串的前三个与三个空格的最终结果。刚开始做的时候就是认为长的一个串一定不要添加空格导致后面否定了一些状态。那么有状态转移方程f[i][j] = max{ f[i-1][j]+val[s1[i]]['-'], f[i][j-1]+val['-'][s2[j]], f[i-1][j-1]+val[s1[i]][s2[j]]
阅读全文
摘要:该题题意为给定一个序列,这个序列能够按照栈的规则进行进出,只不过每个位置的数具有一个数值,每次用出来的顺序减1乘以这个数值,求最后的综合最小。我们有这样的设想,对于一个序列 A B C ... Z,他们有相对应的数值 value[A], value[B] ... value[Z],现在对整个串进行分析,我们试图分析能否找到该问题的子问题,设f[i][j] 为 i 到 j 这个序列能够出来的最小值,那么对于第i号元素来说,我们有如下选择,先出去若干个元素再让a出去,对于某一个区间,我们又可以细分下去。为什么要选择 i 号元素来考虑,因为我们考虑 i 号元素时,选择其他的元素段来考虑都将是一个连续
阅读全文
摘要:求一条从一点出发来回的最长路。将问题转化为从某点出发的到达N点的两条不相交的路径。定义dp[i][j]表示第一个点到达i点,第二个点到达j点所经过的最多顶点数,初始状态为dp[1][1] = 1表示从1,1点出发经过的顶点数为1.动态方程:dp[i][j] = max( dp[i][k] + 1 ) 前提是 k,j 之间有边; 整个状态不去更新dp[i][i],因为如果更新了这个状态就可能使得最优解中包含了相同的点。代码如下:#include <cstring>#include <cstdio>#include <cstdlib>#include <m
阅读全文
摘要:这题如果采用普通的DP方程的话果断TLE。所以需要对DP方程进行优化。由于这里龙珠可以随意选取,所以龙珠的编号也就没有了什么意义了,所以直接先对龙珠进行排序,我们只要保证其位置和花费同步排序就可以了。接下来就是优化了,这个部分可以见代码,在上一题中使用的同步滑动指针,这里则不然,需要根据数值来异步滑动指针。代码如下:#include <cstdlib>#include <cstring>#include <cstdio>#include <algorithm>#define INF 0x7f7f7f7fusing namespace std;in
阅读全文
摘要:Description韩父有N个儿子,分别是韩一,韩二…韩N。由于韩家演技功底深厚,加上他们间的密切配合,演出获得了巨大成功,票房甚至高达2000万。舟子是名很有威望的公知,可是他表面上两袖清风实则内心阴暗,看到韩家红红火火,嫉妒心遂起,便发微薄调侃韩二们站成一列时身高参差不齐。由于舟子的影响力,随口一句便会造成韩家的巨大损失,具体亏损是这样计算的,韩一,韩二…韩N站成一排,损失即为C*(韩i与韩i+1的高度差(1<=i<N))之和,搞不好连女儿都赔了.韩父苦苦思索,决定给韩子们内增高(注意韩子们变矮是不科学的只能增高或什么也不做),增高1cm是很容易的,可是增高10cm花费就很大
阅读全文
摘要:通过枚举每个点作为最小值,再通过动态规划求出以每个点作为最小值的左右区间。代码如下:#include <cstring>#include <cstdio>#include <cstdlib>#include <algorithm>#define MAXN 100005using namespace std;typedef long long int Int64;Int64 seq[MAXN], sum[MAXN], ret;int L[MAXN], R[MAXN], N;int main(){ while (scanf("%d"
阅读全文
摘要:这题虽然说是什么按位DP,其实尼玛不是组合数学么。不过硬是用模板的按位DP实现了,其实也就是记忆化搜索,本题恶心就在于有负数的存在,其实对付它就是把正数的第33位都变成1,用long long来处理,这样既保证了负数小于正数,又可以化成单一的区间了。在按位统计的时候记得当1出现在33位的时候不统计这个1。这题思路也就是先把[a, b]区间内含有一个1,两个1,三个1...的数的个数全部统计出来,一个for循环就能够找出该数字出现在有几个1的一段上,然后再二分查找答案,最后输出。代码如下:#include <cstdlib>#include <cstring>#inclu
阅读全文
摘要:前面用组合数学来写这题实在是被边界条件搞得头昏脑胀,这里就直接按位DP,每次dfs传递0和1的个数这两个参数下去即可。代码如下:#include <cstdlib>#include <cstdio>#include <cstring>using namespace std;int a, b, bit[35], dp[35][35][35];int dfs(int pos, int zero, int one, int limit){ if (pos == -1) { return zero >= one; } if (!limit &&
阅读全文


浙公网安备 33010602011771号