【经典】动态规划

五道经典动态规划问题
1)最大子序列和
题目描述:一个序列,选和最大的子序列
转移方程:sum[i]=max{sum[i-1]+a[i],a[i]}
当前元素的状态是:自己单独一组还是并到前面
最后的答案max{sum[i]}
扩展到二维:最大子矩阵
方法一:而为前缀和 取max
sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+a[i][j]
方法二:二维RMQ
方法三:记录每列的前缀和,枚举子矩阵的上下边界
2)最大修改子序列
题目描述:一个序列,可以修改一次,假设a[i]-->p
转移方程:
f[i][0]=max{f[i-1][0]+a[i],a[i]}
f[i][1]=max{f[i-1][1]+a[i],f[i-1][0]+p,p}
表示到第i个数有没有进行修改
扩展到二维:求待修改的最大子矩阵
for(int tu=1;tu<=n;tu++){
for(int i=1;i<=m;i++)mn[i]=map[tu][i];
for(int i=1;i<=m;i++)a[i]=sum[td][i]-sum[tu][i];
dp[0][1]=-inf;
for(int i=1;i<=m;i++){
dp[i][0]=max(dp[i-1][0]+a[i],a[i]);
dp[i][1]=max(max(dp[i-1][1]+a[i],a[i]-mn[i]+p),dp[i-1][0]+p+a[i]);
}
}
3)数塔问题(数字三角形)递推
4)01背包:
题目描述:n个物品,m为背包容量,wi为物品重量,vi为物品价值
每个物品只有一个
转移方程:
for(int i=1;i<=n;i++)
for(int j=m;j>=wi;j--)
f[j]=max(f[j],f[j-wi]+vi);
01的意思是该物品只有拿和被那两种状态
5)最长上升子序列
转移方程:
for(int i=1;i<=n;i++)
for(int j=1;j<i;j++)
if(a[i]>a[j])
f[i]=max(f[i],f[j+1]);
注意f数组初始化为1
时间复杂度是O(n^2),可以优化。
memset(dp,0x3f,sizeof(dp));
for(int i=1;i<=n;i++)
{
int p=upper_bound(dp+1,dp+n+1,a[i])-dp;
if(a[i]!=dp[p-1])//严格上升序列
dp[p]=a[i];
}
for(int i=1;i<=n+1;i++)
if(dp[i]==maxn)
{
printf("%d\n",i-1);
return 0;
}
dp[i]表示长度为i的最后一个数
时间复杂度O(nlogn)

时间: 2024-08-01 16:03:16

【经典】动态规划的相关文章

hihoCoder - 1038 - 01背包 (经典动态规划问题!!)

#1038 : 01背包 时间限制:20000ms 单点时限:1000ms 内存限制:256MB 描述 且说上一周的故事里,小Hi和小Ho费劲心思终于拿到了茫茫多的奖券!而现在,终于到了小Ho领取奖励的时刻了! 小Ho现在手上有M张奖券,而奖品区有N件奖品,分别标号为1到N,其中第i件奖品需要need(i)张奖券进行兑换,同时也只能兑换一次,为了使得辛苦得到的奖券不白白浪费,小Ho给每件奖品都评了分,其中第i件奖品的评分值为value(i),表示他对这件奖品的喜好值.现在他想知道,凭借他手上的这

经典动态规划 嵌套矩形

描述有n个矩形,每个矩形可以用a,b来描述,表示长和宽.矩形X(a,b)可以嵌套在矩形Y(c,d)中当且仅当a<c,b<d或者b<c,a<d(相当于旋转X90度).例如(1,5)可以嵌套在(6,2)内,但不能嵌套在(3,4)中.你的任务是选出尽可能多的矩形排成一行,使得除最后一个外,每一个矩形都可以嵌套在下一个矩形内. 输入 第一行是一个正正数N(0<N<10),表示测试数据组数, 每组测试数据的第一行是一个正正数n,表示该组测试数据中含有矩形的个数(n<=100

【算法学习笔记】60.经典动态规划 SJTU OJ 1370 赫萝的桃子

Description 赫萝最喜欢吃蜂蜜腌渍的桃子.然而她能够得到的桃子有限,因此赫萝必须精打细算.赫萝在b天内可以得到a个桃子,每天赫萝至少吃一个桃子,她想知道她在a天内有多少种吃桃子的方法.吃桃子的顺序并不重要,也就是说赫萝认为“第一天吃一个桃子第二天吃两个桃子”和“第一天吃两个桃子第二天吃一个桃子”算一种方法. Input Format 每个测试点有多组测试数据. 第一行一个数n,表示测试的数量. 接下来n行每行两个数a, b(a>b). Output Format 输出n行,每行一个数,

读书笔记 - 其他经典动态规划问题

当然,还有LIS, 不过之前总结过了,这次就不贴了 /** 给定两个字符串s1s2s3...sn和t1t2t3...tm 求这两个字符串最长的公共子序列的长度 dp[i][j]表示s序列考虑si,t序列考虑tj时的最长公共子序列 状态转移方程: s[i] == t[j] : dp[i][j] = dp[i-1][j-1] + 1 s[i] != t[j] : dp[i][j] = max(dp[i-1][j], dp[i][j-1]) */ #include <iostream> #inclu

括号匹配(二) -- 经典动态规划

这里的括号匹配 , 如果两个相同的话   就执行下面的  语句 if(cmp(str[i],str[j])) dp[i][j] = min(dp[i][j],dp[i+1][j-1]); 每次确定  从 i 到 j 的需要填补的 括号的时候  就默认  这个 值是  105 1 #include<stdio.h> 2 #include<string.h> 3 #include<math.h> 4 #include<iostream> 5 #include&l

经典动态规划总结

本文持续更新…… 1 给定两组序列 求上下匹配的最大值(POJ1692 Crossed Matchings) 题意:给出两行数,求上下匹配的最多组数是多少. 匹配规则: 1 匹配对的数字必须相同 2 每个匹配必须有且只能有一个匹配与之相交叉,且相交叉的两组匹配数字必须不同 3 一个数最多只能匹配一次 思路: dp[i][j]表示上面取i个数,下面取j个数的最大匹配数 1)若上面不匹配或下面不匹配,则dp[i][j] = max(dp[i - 1][j], dp[i][j - 1] ) 2)若a[

UVA 662 Fast Food +经典动态规划

题目链接:点击进入 以前也碰到过这种类型的dp,感觉就是状态不好定义和转移:原来定义状态的时候总是认为dp[i][j]就应该由dp[i-1][j-1]转移而来,这样的话就会导致需要记忆前面i-1步的所有状态,然后就是转移方程没法写了.对于这道题,我们定义状态dp[i][j]表示前j个餐馆建立i个仓库时的最小代价,然后状态转移为dp[i][j]=dp[i-1][k-1]+cost[k][j],意思是:已经建立的前i-1个仓库负责前k-1个餐馆,然后第i个餐馆负责第k–j个餐馆,其中k<=i<=j

1006 最长公共子序列Lcs(经典动态规划)

传送门 Description 给出两个字符串A B,求A与B的最长公共子序列(子序列不要求是连续的). 比如两个串为: abcicba abdkscab ab是两个串的子序列,abc也是,abca也是,其中abca是这两个字符串最长的子序列. Input 第1行:字符串A 第2行:字符串B (A,B的长度 <= 1000) Output 输出最长的子序列,如果有多个,随意输出1个. Sample Input abcicba abdkscab Sample Output abca 思路 记:Xi

动态规划的简要总结和四个经典问题的c++实现

本文给出了动态规划的简要定义.适用场景.算法实现.并给出了四种经典动态规划:钢条切割求最大收益问题.矩阵链相乘求最小乘法次数问题.最长公共子序列问题.求最小的搜索代价的最优二叉搜索树的c++代码实现. 定义 性质 适用条件 算法实现过程 首先观察问题是否满足最优子结构性质 写出递归等式递归的定义子问题的最优解 求解子问题的最优解 构造最优解 四个经典问题的cpp实现 1 钢条切割 2 矩阵链相乘 3 最长公共子序列 4 最优二叉搜索树 代码下载 1. 定义 动态规划(dynamic progra