@iar
2015-10-29T08:19:35.000000Z
字数 6160
阅读 109
POJ
DP
题目链接
+ 经典的DP问题. 类似的有max triangle sum. 这类题目是找最值, 并且到达每个点有多种路径. 所以是DP. 还有个关键就是DP的3个条件. 以及4要素.
steps[i][j] = Max{steps[i-1][j], steps[i+1][j], steps[i][j-1], steps[i][j+1]} + 1
. 或者说:
node[][]如下:
1 5 6
9 4 7
2 3 8
计算完res00后, path是:
5 4 3
1 0 2
0 0 1
------
reset path[][], 计算res20, path是: 因为到达[2,0]的最优解是7.
0 4 3
1 5 2
7 6 1
接着计算完res10后, path是: 因为没有到达[1,0]的点, 所以返回rs+1= 1.
0 4 3
1 5 2
7 6 1
而不是
0 0 0
1 0 0
0 0 0
还有很重要的点就是: 从上面可以看出来每个子问题计算完之后就是最后的值, 例如[0,0]的最优解是5, 并不会因为我call helper(node, path, 1,0)而改变. 因为很简单: 到达每个点的最优解只有1个!
private int helper(int[][] node, int[][] path, int r, int c) {
// 居然没有base case? 因为这个是求最值的DP, 类似于smilence的笔记里面所说的聚合问题(我觉得应该叫发散, 因为是从要求的点[i,j], 发散求出所有子问题的解, 然后再聚合回到这个点). 所以是topdown, 但不是backtracking.
int rs = 0;
for (int i = 0; i < 4; ++i) {
int next_r = r + dx[i];
int next_c = c + dy[i];
if (isValid(node, r, c, next_r, next_c)) {
if (path[next_r][next_c] > 0) {
rs = Math.max(path[r][c], path[next_r][next_c]+1);
}
else {
rs = Math.max(path[r][c], helper(node, path, next_r, next_c) + 1);
}
}
}
return path[r][c] = rs+1;
}
我一开始想就是: 按照Knight tour/pattern matching那样写. 即
但是我没想到base case怎么写.
helper()的signiture怎么写?
peak helper(node, r, c, Row, Col)
就返回到达[r,c]的最远距离.
private int helperDouban(int[][] node, int[][] path, int r, int c) {
if (path[r][c] > 0) {
return path[r][c];
}
for (int i = 0; i < 4; ++i) {
int next_r = r + dx[i];
int next_c = c + dy[i];
if (isValid(node, r, c, next_r, next_c, node.length, node[0].length)) {
path[r][c] = Math.max(path[r][c], helperDouban(node, path, next_r, next_c) + 1);
}
}
return path[r][c];
}
path[r][c] = Math.max(path[r][c], helperDouban(node, path, next_r, next_c)
.
1 2 3 4
12 13 14 5
11 16 15 6
10 9 8 7
往往DP问题是求解最优解. 即1个值而已. 然后follow up常考返回得到最优解的最优方案, 例如路径之类的.
+ 有2个方法: 一个就是ALgorithm Stanford的课一样, 通过DP table, 一个个找回去到起点. 还有一个方法就是在DP的过程中update 最优方案.
lujing[r][c].addAll(lujing[next_r][next_c]);
. 还有个问题就是, 既然要走4个方向, 并用最长那个, 那么我加了之后, 怎么再换个方向发现更好的时候remove掉呢? 需要一个temp var记录之前加上的长度. 那么这个temp var就要相对于4次换方向来说是global的. 所以就像九章主页君的一个recursion那个题目?, 那样, 使用一个for loop之外的var. 用来记录4次的长度. 只要有更好的, 就remove掉. 再加上这次的list.
private int helperP(int[][] node, int[][] path, List<Integer>[][] list, int r, int c) {
int rs = 0;
int lastSize = 0;
for (int i = 0; i < 4; ++i) {
int rr = r + dx[i];
int cc = c + dy[i];
if (isValid(node, r, c, rr, cc, node.length, node[0].length)) {
if (path[rr][cc] != 0) {
if (rs < path[rr][cc]) {
for (int id = 0; id < lastSize; ++id) {
list[r][c].remove(list[r][c].size() - 1);
}
list[r][c].addAll(list[rr][cc]); //add(node[rr][cc]); //
lastSize = list[rr][cc].size();
rs = path[rr][cc];
}
}
else {
int tmp = helperP(node, path, list, rr, cc);
if (tmp > rs) {
rs = tmp;
for (int id = 0; id < lastSize; ++id) {
list[r][c].remove(list[r][c].size() - 1);
}
list[r][c].addAll(list[rr][cc]); // add(node[rr][cc]);
lastSize = list[rr][cc].size();
}
}
}
}