目标:实现下面游戏的最优路线
规则
- 每个方格的数字代表一个分数值,争取从START开始以最大分数值到达END
- 只能有三种移动方式:向下、向右、向右下
代码思路
- 将思维放在如何在每一步取得当前格可能获得的最大分数值。如下图所示:
根据规则的走法,右下角的值只有3种可能:5、9、13,因此取13。
2、为了计算放在边缘的值与计算不是在边缘的值使用同一套算法,我们可以增加1行与1列做哨兵,如下图所示:
3、计算出最大分数值后,进行终点逆推得出路线,因此每个坐标都需要记录分数与上一个坐标位置。最佳答案如下:
代码实现:
package com.miracle.study.dynamic;
import org.junit.jupiter.api.Test;
import java.util.LinkedList;
import java.util.List;
/**
* @author Miracle
* @date 2021/4/10 16:58
*/
public class BestPath {
public List<int[]> bestChoice(int[][] map){
var ml = map.length;
// 重设地图,需要在地图上与左边铺哨兵,3表示{分数,上一个x位置,上一个y位置}
var dp = new int[ml +1][ml + 1][3];
// 哨兵的值需要足够的小并且一致
for (int i = 1; i < ml + 1; i++){
dp[i][0][0] = -1000;
dp[0][i][0] = -1000;
}
// 循环y轴
for (int y = 1; y < ml + 1; y++){
// 循环x轴
for (int x = 1; x < ml + 1; x++){
// 暂定左上节点为最优节点
var max = dp[x - 1][y - 1][0];
var dx = x - 1;
var dy = y - 1;
// 判断上方节点的分数值情况,如果比当前最大分数值大,就更换为最优节点
if (dp[x][y - 1][0] > max){
max = dp[x][y - 1][0];
dx = x;
}
// 判断左方节点的分数值情况,如果比当前最大分数值大,就更换为最优节点
if (dp[x - 1][y][0] > max){
max = dp[x - 1][y][0];
dy = y;
}
// 计算当前节点的分数
dp[x][y][0] = max + map[x-1][y-1];
// 设置上一个最优节点坐标
dp[x][y][1] = dx;
dp[x][y][2] = dy;
// 打印操作记录
System.out.format("fill:dp=%d, px=%d, py=%d\n", dp[x][y][0], dx, dy);
}
}
// 循环打印每个点的最优值
for (int x = 0; x < ml + 1; x++){
for (int y = 0; y < ml + 1; y++){
System.out.format("%7d ",dp[x][y][0]);
}
System.out.println();
}
int x = ml, y = ml;
// 记录路线坐标
var path = new LinkedList<int[]>();
// 先记录终点 ,坐标减一的目的是为了对应回map
path.addFirst(new int[]{x - 1, y - 1});
// 从终点逆推会始点记录坐标
while (true){
int dx = dp[x][y][1];
int dy = dp[x][y][2];
x = dx;
y = dy;
// 判断是否已经到达始点
if (x == 0 && y == 0){
break;
}
path.addFirst(new int[]{x - 1, y - 1});
}
return path;
}
@Test
public void test(){
var map = new int[][]{
{5, 4, 2, 2},
{8, 0, 5, 7},
{4, 1, 2, 0},
{1, 4, 6, 3}
};
var path = bestChoice(map);
// 循环将坐标点对应回map中
for (int[] i : path){
var x = i[0];
var y = i[1];
System.out.print(map[x][y] + "->");
}
System.out.println("END");
}
}
输出结果如下:
fill:dp=5, px=0, py=0
fill:dp=13, px=1, py=1
fill:dp=17, px=2, py=1
fill:dp=18, px=3, py=1
fill:dp=9, px=1, py=1
fill:dp=13, px=2, py=1
fill:dp=18, px=3, py=1
fill:dp=22, px=4, py=1
fill:dp=11, px=1, py=2
fill:dp=18, px=2, py=2
fill:dp=20, px=3, py=2
fill:dp=28, px=4, py=2
fill:dp=13, px=1, py=3
fill:dp=25, px=2, py=3
fill:dp=25, px=3, py=4
fill:dp=31, px=4, py=3
0 -1000 -1000 -1000 -1000
-1000 5 9 11 13
-1000 13 13 18 25
-1000 17 18 20 25
-1000 18 22 28 31
5->8->4->1->4->6->3->over
Process finished with exit code 0