动态规划
反思和总结
-
如果区分是否需要使用dp
- 一般是最优解问题
- 一般贪心不能正确处理
-
dp几个要素
- 状态的定义
- 几个维度
- 怎么体现不同的状态
- 状态的转移
- 什么东西变动会造成状态转移
- 状态的启动
- 一方面定义初值
- 另一方面确定循环开始的地方,有的时候是从顶向下开始循环,故需要使用记忆化搜索 + 递归的方式
- 状态的定义
-
背包
-
01背包
//01背包基本的写法 for(int i = 1; i <= n; i ++){ for(int j = c; j >= 0; j --){ if(j > weight[i]) dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + v[i]); else dp[i][j] = dp[i - 1][j]; } } //01背包优化写法 for(int i = 1; i <= n; i ++){ for(int j = c; j >= w[i]; j --){ dp[j] = max(dp[j], dp[j - w[i]] + v[i]); } } //完全背包(一个物品可以取多次) for(int i = 1; i <= n; i ++){ for(int j = w[i]; j <= c; j ++){ dp[j] = max(dp[j], dp[j - w[i]] + v[i]); } }
-
题号
-
PIPIOJ 1071: 数塔
-
PIPIOJ 1073: 矩阵取数Ⅰ
-
PIPIOJ 1076: 饭卡
-
PIPIOJ 1078: 等待分配的程序
-
PIPIOJ 1079: PIPI的存钱罐
-
PIPIOJ 1080: 最长上升子序列Ⅰ
-
PIPIOJ 1083: 最长公共子序列Ⅰ
-
PIPIOJ 1092: 地头蛇PIPI
-
PIPIOJ 1022: 淘金
-
PIPIOJ 1093: 滑雪
-
PIPIOJ 1088: 回文串询问Ⅱ
-
PIPIOJ 1019: 堆石子
分析
- 1076
- 问题可以拆分为少5快钱容量的背包问题 + 用5块钱买最多东西的贪心问题
- 1078
- 问题可以化解为在总时间/2的情况下,选择尽可能多的东西,也是背包问题
- 考虑两个背包一起拿东西不方便,直接从结果的情况出发分析,猜出最终的大致情况,从而降维成为单背包问题
- 1079
- 也是背包问题,只是这题需要对dp初值设置为INF,而dp00设置为0,并且是最小背包问题,从而使得刚好选择合适容量的有解
- 1080
- 这题要是最长上升子序列,要和最大连续和区分
- 状态的定义为对应下标的最大长度
- 状态的更新,由于是子序列,不是子串,所以需要从当前下标向前看,找到满足条件的最大值
- 1083
- 状态的定义是对应下标的字符串包含的子序列长度
- 状态的转移取绝于当前字符
- 1092
- 状态的定义包含了两种的可能,状态的转移就是在不同的可能中移动
- 1022
- 降维,先按1092算出所有的行,在将行看成一列,再次来一次1092
- 1093
- 记忆化搜索,从上往下寻找,使用dp定义状态,保存数据
- 1088
- 一方面使用dp来判断是不是回文串
- 另一方面来使用容斥定理计算回文串子串的个数
- 两者可以同时进行
- 1019
- 这题也是从下往上搜索,故需要记忆化搜索