问题导入——最短路径的选择
问题描述
假设我们有一个 n 乘以 n 的矩阵 w[n][n]。矩阵存储的都是正整数。棋子起始位置在左上角,终止位置在右下角。我们将棋子从左上角移到右下角。每次只能向右或者向下移动一位。整个过程,会有多种不同的路径可以选择。我们把每条路径经过的数字加起来看作路径的长度。那从左上角到右下角的最短路径长度是多少呢
两种思路
从起点出发,按照可见方向得最短方向进行前进
- 所以,显而易见得,只从当前结点找最短路径只能实现的局部的最优解,是有很大的局限性。
从终点出发,我们逆着来
按照上面画的图,其实这里面包含了逻辑推理,彼此之间是能够相互确定最小值。将上面的图简化一下,变成下面的阶段图。
- 通过初始阶段是可以确定阶段一,从而确定阶段二,以此类推,自然而然的就确定出阶段六,也就是终点的最短路径。
代码实现(这里并没有具体的实现,只是做了一个简单的样板)
- 这一切都是建立在上述的推理上,彼此都是可以相互确定的
- 最基本的语句是,sp[i][j]=min(sp[i-1][j],sp[i][j-1])+sp[i][j]
int minDistDP(int[][] martrix,int n){
//生成状态数组,用来保存到当前节点的路径
int[][] states = new int[n][n];
//初始化矩阵的第一行和第一列
int sum = 0;
for(int i = 0;i < n;i ++){
sum += martrix[0][i];
states[0][i] = sum;
}
sum = 0;
for(int i = 0;i < n;i ++){
sum += martrix[0][i];
states[0][i] = sum;
}
//实现推理
//注意,这里每一个格子都是可以确定进行推理的,所以要遍历所有的格子
for (int i = 1; i < n; ++i)
{
for(int j =1;j < n; j ++){
state[i][j] = martrix[i][j]+min(state[i][j-1],state[i-1][j+1]);
}
}
return state[n-1][n-1];
}
总结
- 虽说是动态规划问题,但是每一个值都是可以通过前一个值进行间接推理的,并且当前状态的最优解,是建立在前一个状态的最优解上的。
- 理论上的可以使用递归进行实现,但是会造成重复计算。这里使用数组将计算的结果临时进行保存。