7.13
p1057 金明的预算方案[分组背包], 1.5h
f[v] = max{f[v], f[v - c[i][j]] + w[i][j]}
*注意读题,主件的编号和物品编号相同,这里调了1h
*注意逗号的使用
@Ural p1018 Binary Apple Tree[树形], 1.5h{大量参考题解}
f[i][j] = max(f[tree[i].l][k] + f[tree[i].r][j-k-1] + tree[i].v)
*初始化中使用-1标记未计算(避免重复0)
*递归建树 -> 寻找儿子的过程可利用邻接表优化[未验证]
*记忆化搜索f[t][q]初始化为0, 根节点值最后计算, 注意特殊情况0
*特别注意, 把题目中的 边权 转换为 点权, 以及q的相关变化
7.15
#p1051 选课[树形DP], 1.5h
f[i][j] = f[tree[i].r][j] (左子树空)
f[tree[i].l][k]+f[tree[i].r][j-k-1]+tree[i].v (左子树非空)
*多叉树转二叉树 -> 左儿子, 右兄弟
if (!left[a]) tree[a].l = i;
else tree[left[a]].r = i;
left[a] = i;
**记忆化搜索过程为什么不能直接返回int -> 实验证实会引起错误, 原因不明 -> 盲目合并语句所致
if (f[i][j] || i == 0 || j <= 0) return 0;
应为
if (i == 0 || j <= 0) return 0;
if (f[i][j]) return f[i][j] ;
-> 合并此类控制边界语句应注意返回值
**泛化背包做法 http://archive.cnblogs.com/a/2091585/
p1087 sumsets[完全背包+统计方案数], 60min
f[i][j] = f[i-1][j] + f[i][j-c[i]] (f[0][0] = 1)
一开始盲目列表找递推式, 尝试无果. 后发现题目本意即完全背包问题, 2^k是物体, 实现时注意降维.
*统计方案总数问题递推式中max改为+, 注意f[0] = 1
*此类问题注意高精度的实现 或者 mod(注意题目中要求, 如本题9位精度)
*另一种方程 f[i] = f[i-1] (i=2k+1) -> 已通过观察得到
f[i-1] + f[i/2](i=2k) -> 动机是什么?
p1079 数字三角形3[坐标DP], 30min
f[i][j] = max(f[i+1][j], f[i+1][j+1]) + A[i][j] (0 < j <= i <= n/2)
通过分析可知, 指定点(n/2, n/2)前(i, i)必取, 而其后和一般数字三角做法相同, 终点为f[n/2][n/2]
故最终答案Σf(i,i)_(0 < i < n/2) + f[n/2][n/2]
*坐标问题注意分析起点和终点的要求
p1084 数字三角形4[坐标DP], 10min
(x, y)前: f1[i][j] = max(f1[i-1][j-1], f1[i-1][j]) + A[i][j] (0 < j <= i <= x)
(x, y)后: f2[i][j] = max(f2[i+1][j], f2[i+1][j+1]) + A[i][j]
分析可知, (x, y)前顺推, 指定终点为(x, y), 起点必然为(1, 1), (x, y)后逆推, 指定终点为(x, y)
故最终答案为f1[x][y] + f2[x][y] - A[x][y]
p1076 数字三角形2[判定性DP], 30min
f[i][j][(k+A[i][j])%100] = f[i+1][j][k] | f[i+1][j+1][k]
通过增加维度转化为判定性问题, 由于取模所以k的顺序不确定, 因而用坐标来控制顺序
7.16
#p1048 田忌赛马[贪心 + DP], 1.5h
1.O(N + NlogN), [题解来自网络]思想是这样的, 先把各组马的速度从大到小排序, 然后用田忌的马顺序与齐威王的马比较
if(田忌的马快)比较下一对马;
else if(田忌的马慢)用田忌最慢的马和齐威王的这匹马赛
else{
从未进行比赛的速度小的马开始从后往前比
if(田忌的马快) //这里是必须的,否则如果是90 73 71 和 90 70 70 ,那么没有这个是
继续往前比 //2-1,有了的话就是2+0,非常重要
else 用这匹马和刚才跑平的齐威王的马比
//总之原则就是如果这匹马不能赢,就让他和比他快很多的马比,这样保持速度较快的马
}
*while循环条件, f1 <= r1
2.O(N^2 + NlogN), 来自:http://hi.baidu.com/lyltim/blog/item/57fccd1153ea851eb9127ba9.html
[贪心分析]
1、如果田忌剩下的马中最强的马都赢不了齐王剩下的最强的马,那么应该用最差的一匹马去输给齐王最强的马。
2、如果田忌剩下的马中最强的马可以赢齐王剩下的最强的马,那就用这匹马去赢齐王剩下的最强的马。
3、如果田忌剩下的马中最强的马和齐王剩下的最强的马打平的话,可以选择打平或者用最差的马输掉比赛。
[DP做法]
f[i,j]=max{f[i-1,j]+g[n-(i-j)+1,i],f[i-1,j-1]+g[j,i]}
其中g[i,j]表示田忌的马和齐王的马分别按照由强到弱的顺序排序之后,田忌的第i匹马和齐王的第j匹马赛跑所能取得的盈利
#p1402 乌龟棋[路径DP], 1.5h
f[i][j][k][l] = max(f[i-1][j][k][l], f[i][j-1][k][l], f[i][j][k-1][l], f[i][j][k][l-1]) + A[i+2j+3k+4l+1]
以卡片数为阶段, 状态f[i][j][k][l]表示还剩下每种牌各多少张时得到的最大值, 注意起始位置
*卡了1h因为被05的过河和08的传纸条限制思维, 认为以所在位置为阶段, 想对空间降维
*[降维条件]状态各维度存在等量关系, 因而可减少时间复杂度, 但是不能改变空间复杂度
#p1052 没有上司的舞会[树形DP], 1.5h
f[i][0] = ∑max{f[j][0], f[j][1]} (j∈i.son), i不参加
f[i][1] = ∑f[j][0] + tree[i].v (j∈i.son), i参加
[边界]若i为叶节点, f[i][0] = 0, f[i][1] = tree[i].v
前半个小时写完了多叉转二叉, 证明了left[]的必要性.
*状态设计问题: 没有区分i参加和不参加的情况, 并认为f[i]由f[j](不取i, j是i的儿子)和f[k](取i, k是i的孙子)推得
*叶节点的初始化, 对于f[i][]求和而非取最大值, 选取根节点而非叶节点(需要两个数组映射)
*由于30min时方程考虑不周, 导致多次修正, 因而卡了1h. 务必要先写出正确方程.
7.18
p1134 CCR的中考之考前计划[模拟], 50min
语文题, 题目描述问题很大, 浪费了0.5h, google了一个std之后得到正确题意. 题目是类似beads的模拟题, 将环从某处打断, 使得两端科目类型相同的天数最多.寻找相同科目的条件A[j+1] = 'w' || A[j+1] = A[i].
*环状问题的处理方法: 2n-1, 在本题中双方向同时进行不妨3n-2
#p1088 treat[区间DP], 20min
f[i][j] = max{f[i+1][j] + A[i] * (n+i-j), f[i][j-1] + A[j] * (n+i-j)} (0 < i < j <= n)
f[i][j]表示[i, j]未取时的最大值, 初始化f[i][j] = A[i] * n, 以长度l为阶段, 故 j = i+l-1
*考虑第k次取数, k = n - (i-j+1) + 1(包括这次), 昨天没想到这点卡了很久
*在网上找到了另外一种设置状态的方法, 设f[i][j]是取i个数, 左边取j个, 方程:
f[i][j] = max(f[i - 1][j - 1] + i * A[j], f[i - 1][j] + i * A[n - (i - 1 - j)])
-> 猜想动机: 存在等式 前 + 后 = 总数, 状态的设置都是为了描述着三个量.
agirnet[Krusal], 20min
复习并查集实现的Krusal
p1307 联络员[Krusal],50min
必选边先使用set[find(e[i].u)] = find(e[i].v)合并, 并记录权和, 然后按一般的Krusal做即可.
*使用stdlib.h的qsort间接排序失败, 原因不知(20min)
*注意此时k++不能并入下一行语句中, 否则++k和k值不同导致输入错误:
++k,
scanf("%d%d%d", &must[k].u, &must[k].v, &must[k].w);
7.20
p1113 魔族密码[LIS模型], 40min, 6WA
f[i] = max{f[j] + 1} (A[j]为A[i]前缀, 1 <= j < i)
*注意最大值不一定在f[n]中, 需要对f[1] -> f[n]进行循环检查, 卡了30min
p1187 小飞侠的游园方案[0/1背包], 15min
f[i][j] = max(f[i-1][j], f[i-1][j - c[i]] + w[i])
存在可能未装满的情况, 故循环检查f[n][]即可
#p1190 积木城堡[背包DP], 1.5h, 6WA
f[k][j] = f[k][j - w[i]] (j - w[i] >= 0)
类似分组背包的做法, 记录每组物品的所有可能值, 若f[1..k][V]同时为true, 则V为最值. 也可以在读入时, 循环检查每组物品的可能值.
*注意读题, 尤其是各种数据范围, 不要重复去年第二题!!!
*读入时注意MAXn+1, 留意-1的情况; 显然答案不会超过所有城堡的最小高度(而非最大).
*题目中并没有强调按顺序取积木, 因而一开始打了模拟, 之后手贱去Google. 对于这类问题, 在提交后若发现则应继续思考. 此外不要给题目增加条件.
**注意这类确定各组物品所有可能值写法 和 最优值写法的区别
*一组测试数据:
5
87 76 65 54 32 21 23 -1
64 75 25 63 76 23 75 13 64 23 -1
09 78 76 46 32 45 23 -1
23 34 45 -1
12 34 23 -1
p1213 嵌套矩形[LIS模型/DAG最长路], 1h, 9WA
(1)f[i] = max(f[j] + 1) (rect[i]可嵌套rect[j])
*初始化f[] = 1; 初始化为0, 输出+1会导致错误, 原因不知.
-> 另一种写法(by Ylen): f[0] = 0, f[] = INT_MAX;
*注意题目没有强调矩形间存在顺序, 因而存在后效性. 易知面积小的矩形不会嵌套面积大的矩形, 因而以面积为关键字对rect进行间接排序.
(2)f[i] = max(f[j] + 1 | (i,j)∈G)
若rect[i]可嵌套rect[j], 则建立一条从i到j的边, 求最长路即可