动态规划例题讲解
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
时间复杂度:O(N^2)
最长上升子序列
换一种状态表示方法 令f[i]表示长度为i的上升子序列的结尾数字 最小是多少
初始f[0]=-inf,f[i]=inf(inf为无穷大,可取 值为大于任意ai绝对值的一个数字)
最长上升子序列
F[0] 初始 插入a1后
插入a2后 插入a3后 插入a4后 插入a5后 插入a6后 插入a7后 插入a8后 插入a9后
给出一个数列{a1,a2,...,an},要求你选出尽 量多的元素,使这些元素按其相对位置单 调递增。
Sample Input 9 589231746
Sample Output 4
最长上升子序列
算法:动态规划 令f[i]表示以ai为结尾的最长上升子序列的 长度 转移方程: f[i]=max(f[ j],1<=j<i,a[ j]<a[i])+1
0/1背包问题
令f[i,j]表示考虑完前i项物品,并且当前背 包承重不大于j的情况下能获得的最大价值 f[i,j]=max( f[i-1,j], //不选第i项物品 f[i-1,j–w[i]]+v[i]) //选择第i项物品 边界条件f[0,i]=0 目标f[n,limit]
0/1背包问题
动态规划例题讲解
山东师大附中 魏铭
Preview
本节课主要通过几道例题,总揽NOIp中较 常见的动态规划模型,不会过多涉及优化 内容。
Preview
最长上升子序列 内存碎片 背包问题 最长公共子序列 石子合并
括号序列 决斗 三取方格数 选课 贪吃的九头龙
最长上升子序列
选人
将所有人按照智商排序,以情商为关键字, 求最长上升子序列的长度即可。
内存碎片
N个内存申请请求,申请长度为L[i]的内存 块c[i]次。 当程序申请长度为L的内存时,也可以给它 分配一块长度为L’(L’>L)的更大的内 存块。 内存长度种类不超过K。 求最少需要的内存。
内存碎片
时间复杂度O(N^2*K)
0/1背包问题
共有N件物品,每件物品有一定的重量w[i] 和一定的价值v[i],现在我们有一个最大载 重量limit的包,问放入哪些物品能使得总 价值最高?
w[i]和v[i]均为整数,N<=100, limit<=10000
0/1背包问题
SampleInput SampleOutput 3 100 1400 30 300 80 1200 10 200 共有3件物品 重Hale Waihona Puke Baidu分别为30/80/10 价值分别为300/1200/200 背包最大载重量为100
Sample Input 32 10 1 11 1 20 1
3个内存申请 最多2种长度
Sample Output 42
方案: 两个11,一个20
内存碎片
算法:动态规划 先将所有L[i]排序。 112344678 222446688 113366688 233377778
这一行是内存申请的长度
这三行是内存分配的可能长度
内存碎片
一种内存长度覆盖的区间必定是连续的, 并且该内存长度等于覆盖区间最后一个内 存申请操作的长度。 令f[i,j]表示考虑完前i个内存申请操作,并 且已经使用完j种内存长度的最少需要的内 存。
内存碎片
f[i,j]=min{ f[k,j-1]+ (c[k+1]+c[k+2]+...+c[i])*L[i],0<=k<i} 预处理sc[i]=c[1]+c[2]+...+c[i] f[i,j]=min{ f[k,j-1]+(sc[i]-sc[k])*L[i],0<=k<i)}
多重背包问题
共有N种物品,每种物品有一定的重量w[i] 和一定的价值v[i],每种物品有c[i]个。现在 我们有一个最大载重量limit的包,问放入 哪些物品能使得总价值最高?
w[i]和v[i]均为整数,N<=100, limit<=10000
多重背包问题
Sample Input Sample Output 3 100 1700 30 300 2 方案: 80 1200 1 1件物品1 10 200 8 7件物品3 共有3件物品 重量分别为30/80/10 价值分别为300/1200/200 数量分别为2/1/8 背包最大载重量为100
F[1] inf 5
5 5 2 2 1 1 1 1
F[2] inf inf
8 8 8 3 3 3 3 3
F[3] inf inf
inf 9 9 9 9 7 4 4
F[4] inf inf
inf inf inf inf inf inf inf 6
-inf -inf
-inf -inf -inf -inf -inf -inf -inf -inf
完全背包问题
共有N种物品,每种物品有一定的重量w[i] 和一定的价值v[i],每种物品有无限个。现 在我们有一个最大载重量limit的包,问放 入哪些物品能使得总价值最高?
w[i]和v[i]均为整数,N<=100, limit<=10000
完全背包问题
fillchar(f,sizeof(f),0); for i:=1 to n do for j:= w[i] to limit do f[ j] = max(f[ j], f[ j-w[i]]+v[i]); writeln(f[limit]);
Sample Input 5 8 9 2 3 1 7 4 6
最长上升子序列
f[]是单调递增的,因为如果有i<j且 f[i]>=f[ j],那么f[i]必定可以被f[ j]的方案所 更新。 每处理到一个ai,我们要找到一个k满足 f[k–1]<ai且f[k]>=ai,并用ai更新f[k],最 终max(k|f[k]!=inf)就是答案。 可以通过二分查找将时间复杂度降至 O(NlogN)
我们注意到,f[i,j]仅与f[i-1,j]和 f[i-1,j-w[i]]有关,因此没必要保存二维数 组 令f[i]表示背包承重不大于i的情况下最大价 值
0/1背包问题
fillchar(f,sizeof(f),0); for i:=1 to n do for j:=limit downto w[i] do f[ j] = max(f[ j], f[ j-w[i]]+v[i]); writeln(f[limit]);
最长上升子序列
换一种状态表示方法 令f[i]表示长度为i的上升子序列的结尾数字 最小是多少
初始f[0]=-inf,f[i]=inf(inf为无穷大,可取 值为大于任意ai绝对值的一个数字)
最长上升子序列
F[0] 初始 插入a1后
插入a2后 插入a3后 插入a4后 插入a5后 插入a6后 插入a7后 插入a8后 插入a9后
给出一个数列{a1,a2,...,an},要求你选出尽 量多的元素,使这些元素按其相对位置单 调递增。
Sample Input 9 589231746
Sample Output 4
最长上升子序列
算法:动态规划 令f[i]表示以ai为结尾的最长上升子序列的 长度 转移方程: f[i]=max(f[ j],1<=j<i,a[ j]<a[i])+1
0/1背包问题
令f[i,j]表示考虑完前i项物品,并且当前背 包承重不大于j的情况下能获得的最大价值 f[i,j]=max( f[i-1,j], //不选第i项物品 f[i-1,j–w[i]]+v[i]) //选择第i项物品 边界条件f[0,i]=0 目标f[n,limit]
0/1背包问题
动态规划例题讲解
山东师大附中 魏铭
Preview
本节课主要通过几道例题,总揽NOIp中较 常见的动态规划模型,不会过多涉及优化 内容。
Preview
最长上升子序列 内存碎片 背包问题 最长公共子序列 石子合并
括号序列 决斗 三取方格数 选课 贪吃的九头龙
最长上升子序列
选人
将所有人按照智商排序,以情商为关键字, 求最长上升子序列的长度即可。
内存碎片
N个内存申请请求,申请长度为L[i]的内存 块c[i]次。 当程序申请长度为L的内存时,也可以给它 分配一块长度为L’(L’>L)的更大的内 存块。 内存长度种类不超过K。 求最少需要的内存。
内存碎片
时间复杂度O(N^2*K)
0/1背包问题
共有N件物品,每件物品有一定的重量w[i] 和一定的价值v[i],现在我们有一个最大载 重量limit的包,问放入哪些物品能使得总 价值最高?
w[i]和v[i]均为整数,N<=100, limit<=10000
0/1背包问题
SampleInput SampleOutput 3 100 1400 30 300 80 1200 10 200 共有3件物品 重Hale Waihona Puke Baidu分别为30/80/10 价值分别为300/1200/200 背包最大载重量为100
Sample Input 32 10 1 11 1 20 1
3个内存申请 最多2种长度
Sample Output 42
方案: 两个11,一个20
内存碎片
算法:动态规划 先将所有L[i]排序。 112344678 222446688 113366688 233377778
这一行是内存申请的长度
这三行是内存分配的可能长度
内存碎片
一种内存长度覆盖的区间必定是连续的, 并且该内存长度等于覆盖区间最后一个内 存申请操作的长度。 令f[i,j]表示考虑完前i个内存申请操作,并 且已经使用完j种内存长度的最少需要的内 存。
内存碎片
f[i,j]=min{ f[k,j-1]+ (c[k+1]+c[k+2]+...+c[i])*L[i],0<=k<i} 预处理sc[i]=c[1]+c[2]+...+c[i] f[i,j]=min{ f[k,j-1]+(sc[i]-sc[k])*L[i],0<=k<i)}
多重背包问题
共有N种物品,每种物品有一定的重量w[i] 和一定的价值v[i],每种物品有c[i]个。现在 我们有一个最大载重量limit的包,问放入 哪些物品能使得总价值最高?
w[i]和v[i]均为整数,N<=100, limit<=10000
多重背包问题
Sample Input Sample Output 3 100 1700 30 300 2 方案: 80 1200 1 1件物品1 10 200 8 7件物品3 共有3件物品 重量分别为30/80/10 价值分别为300/1200/200 数量分别为2/1/8 背包最大载重量为100
F[1] inf 5
5 5 2 2 1 1 1 1
F[2] inf inf
8 8 8 3 3 3 3 3
F[3] inf inf
inf 9 9 9 9 7 4 4
F[4] inf inf
inf inf inf inf inf inf inf 6
-inf -inf
-inf -inf -inf -inf -inf -inf -inf -inf
完全背包问题
共有N种物品,每种物品有一定的重量w[i] 和一定的价值v[i],每种物品有无限个。现 在我们有一个最大载重量limit的包,问放 入哪些物品能使得总价值最高?
w[i]和v[i]均为整数,N<=100, limit<=10000
完全背包问题
fillchar(f,sizeof(f),0); for i:=1 to n do for j:= w[i] to limit do f[ j] = max(f[ j], f[ j-w[i]]+v[i]); writeln(f[limit]);
Sample Input 5 8 9 2 3 1 7 4 6
最长上升子序列
f[]是单调递增的,因为如果有i<j且 f[i]>=f[ j],那么f[i]必定可以被f[ j]的方案所 更新。 每处理到一个ai,我们要找到一个k满足 f[k–1]<ai且f[k]>=ai,并用ai更新f[k],最 终max(k|f[k]!=inf)就是答案。 可以通过二分查找将时间复杂度降至 O(NlogN)
我们注意到,f[i,j]仅与f[i-1,j]和 f[i-1,j-w[i]]有关,因此没必要保存二维数 组 令f[i]表示背包承重不大于i的情况下最大价 值
0/1背包问题
fillchar(f,sizeof(f),0); for i:=1 to n do for j:=limit downto w[i] do f[ j] = max(f[ j], f[ j-w[i]]+v[i]); writeln(f[limit]);