【算法基础课】笔记05——动态规划

动态规划

从集合的角度理解

  1. 状态表示 f(i, j)
  • 集合:只考虑前i个物品并且总体积<=j的所有选法
  • 属性:Max + Min + 数量
  1. 状态计算——集合划分(不含i, 含i)
    画出面包图,表示出可能的各种状态
    分析方法:先不考虑第 i 件物品,变为 f(i-1, j)和f(i -1, j - vi) + wi

背包问题

01背包

每个物品用一次

滚动数组优化:(原因)

  • f(i)只用到了f(i - 1),所以可以把前面的都省掉,只看j
  • 体积 j - v[i] <=j——>01背包倒序求,防止重复取用

完全背包

每个物品无限个
属性:(Max)

  1. 去掉k个i
  2. 求Max,f[i - 1, j - k * v[i]]
  3. 加上k个i
    f[i, j] = max( f[i - 1, j - v[i] * k] + w[i] * k) ;

优化:进行一个对齐的操作
顺序:小——>大

多重背包

每个物品有限定个
f[i, j] = max( f[i - 1, j - v[i] * k] + w[i] * k) ;
二进制分组优化
打包

  1. 1,2,4,8,…,2k,c (c < 2{k+1})

(滑动窗口最大值:单调队列优化)

分组背包

i个——>i组

线性DP

维度升序考虑

最长上升子序列

集合:所有以第 i 个数结尾的上升子序列
属性:Max
a j = M a x ( f [ j ] + 1 ) 满 足 a j < a i , j = 0 , 1 , 2 , . . . , i − 1 a_j = Max(f[j] + 1)\\ 满足a_j < a_i,j = 0,1,2,...,i-1 aj=Max(f[j]+1)aj<ai,j=0,1,2,...,i1
保存序列:记录转移过程
优化:存结尾最小的上升子序列
因为小的末尾一定可以接到大的头上
二分找(其实STL也很好)

最长公共子序列

集合:所有再第一个序列的前 i 个字母中出现,且再第二个序列的前 j 个
分三种状况分析,一个不等2,两个都等1

dp[i][j] = max (dp[i-1][j], dp[i][j-1]);
            if(a[i] == b[j])
                dp[i][j] = dp[i-1][j-1] + 1;

最短编辑距离

集合:所有将a变成b的操作方式
状态计算:

  • 删:f(i-1, j) + 1
  • 增:f(i, j-1) + 1
  • 改:f(i-1, j-1) + (a[i] != b[j]) (不等就要加一次
    f(i, j) = min(删,增,改)

区间DP

补一道例题:https://www.bilibili.com/video/BV1eF411p7kw?spm_id_from=333.999.0.0

集合:所有将第 i 堆石子合并为一堆石子的合并方式
属性: Min
过程分析:
(最后一步)最后的合并代价 + 前缀和求所有质量之和
f [ i ] [ j ] = m i n ( s [ j ] − s [ i − 1 ] + f [ i , k ] + f [ k + 1 , j ] ) f[i][j] = min( s[j] - s[i -1] + f[i, k] + f[k +1, j]) f[i][j]=min(s[j]s[i1]+f[i,k]+f[k+1,j])
枚举长度、起点、分界点k

在这里插入图片描述

计数DP

整数划分

  1. 完全背包做法
    关键在于抽象转化
    集合:1~i 选,体积恰好是 j 的数量
  2. 其他
    集合:总和为 i ,总个数为 j

数位统计DP

count(n, x) : 1 ~ n 中 x 出现的次数
来自wx大佬:
(原图链接)
https://www.acwing.com/file_system/file/content/whole/index/content/3952654/
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AW1mfBEh-1645330640248)(C:\Users\bingtongsuan\AppData\Roaming\Typora\typora-user-images\image-20220218120106802.png)]

状态压缩DP

补一道例题:https://www.bilibili.com/video/BV1nS4y1V7Ee?spm_id_from=333.999.0.0

蒙德里安的梦想

横着放完,竖的就自然出来了
f[i][j] : 前 i -1 列已经摆好,从i - 1列伸出到第 i 列的所有方案的状态( j 记录哪些列伸出了横向方格)(二进制表示)

i 表列,j、 k 表行
f[i, j] += f[i - 1, k]
满足条件:
1.** (j & k) == 0** (没冲突)
2.** j | k** 不存在连续奇数个0 (没空隙)

纵向看,必须要有连续偶数个空位(用来放置竖的方块)

最短Hamilton路径

  • f[i][j]:所有从0走到 j ,走过的所有点是 i 的所有路径
  • 0—…—>k—> j
    f[i - (1 << j)][k] + w[k][j]

i >> j & 1 代表 j 在 i 状态里
i - (1 << j) 代表 除去 j 这个状态

树形DP

经典老题:没有上司的舞会
(某人因为root搞错)
推荐看我视频讲解bushi
https://www.bilibili.com/video/BV1wL411w7t1?spm_id_from=333.999.0.0

记忆化搜索

经典老题:滑雪

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值