这是我对经典硬币收集DP问题的解决方案。一般来说,在做DP问题时,我总觉得printPath()
步骤非常笨拙,比实际问题本身更混乱。
在这种情况下,从右下角开始,如果向上或向左的方向上的值是平局,只需上升即可。否则,选择包含更高或更高值的方向。如果我们到达第一排,就继续向左走。如果我们到达第一列,就继续上去。
是否有更简洁的方式printPath()
?
/*
given a grid
where o = coin
return the max coins you can get by only moving right or down
*/
var grid = [
['-','-','o','-','-','o'],
['-','-','-','o','-','-'],
['-','o','-','-','o','-'],
['-','-','-','o','-','-'],
['o','-','-','-','o','-'],
['-','-','o','-','-','o'],
];
function initTable(m, n, f) {
var T = [];
for (var r = 0; r < m; r++)
T.push(Array(n).fill(f));
return T;
}
function coinCollection(grid) {
var m = grid.length, n = grid[0].length;
var T = initTable(m+1, n+1, 0);
for (var r = 1; r < m+1; r++) {
for (var c = 1; c < n+1; c++) {
var C = grid[r-1][c-1] === 'o' ? 1 : 0;
T[r][c] = Math.max(T[r-1][c], T[r][c-1])+C;
}
}
console.log({ T });
printPath(T, m, n);
return T[m][n];
}
function printPath(T, r, c) {
var res = [];
while (r !== 1 && c !== 1) {
res.push([r, c]);
if (T[r-1][c] === T[c][r-1] || T[r-1][c] > T[r][c-1]) { // tie or up is more
console.log(r, c, '↑');
r--;
} else { // left is more
console.log(r, c, '←');
c--;
}
}
if (r === 1) { // hit first row, keep left until origin
while (c !== 1) {
res.push([r, c]);
console.log(r, c, '←');
c--;
}
} else if (c === 1) { // hit first col, keep up until origin
while (r !== 1) {
res.push([r, c]);
console.log(r, c, '↑');
r--;
}
}
console.log(r, c);
res.push([r, c]);
console.log({ grid, max_coins_path: res.map(([r,c]) => [r-1,c-1]).reverse() });
}
coinCollection(grid);