-
Notifications
You must be signed in to change notification settings - Fork 48
/
Copy pathChessboard.swift
149 lines (127 loc) · 4.65 KB
/
Chessboard.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
//
// Chessboard.swift
// DynamicProgramming
//
// Created by ggl on 2020/8/23.
// Copyright © 2020 ggl. All rights reserved.
// 棋盘最短路径长度问题
import Foundation
/**
* 假设我们有一个 n 乘以 n 的矩阵 w[n][n]。矩阵存储的都是正整数。
* 棋子起始位置在左上角,终止位置在右下角。我们将棋子从左上角移动到右下角。
* 每次只能向右或者向下移动一位。从左上角到右下角,会有很多不同的路径可以走。
* 我们把每条路径经过的数字加起来看作路径的长度。
* 那从左上角移动到右下角的最短路径长度是多少呢?
*/
/// 动态规划求解棋盘最短路径问题(状态转移表)
///
/// - Parameter chessboard: 棋盘数据
/// - Returns: 最短路径
func chessboardMinDistDP(chessboard: [[Int]]) -> Int {
// 状态二维数组,用来存储每个结点的最短路径长度,x表示棋盘横轴,y表示棋盘纵轴
var states = [[Int]](repeating: [Int](repeating:0 , count: chessboard.count), count: chessboard.count)
// 初始化第一行数据
var sum = 0
for j in 0..<chessboard.count {
sum += chessboard[0][j]
states[0][j] = sum
}
// 初始化第一列数据
sum = 0
for i in 0..<chessboard.count {
sum += chessboard[i][0]
states[i][0] = sum
}
// 剩下的其他结点
for i in 1..<chessboard.count {
for j in 1..<chessboard.count {
let minValue = Swift.min(states[i][j-1], states[i-1][j])
states[i][j] = minValue + chessboard[i][j]
}
}
// 返回最小路径
return states[chessboard.count-1][chessboard.count-1]
}
/// 动态规划求解棋盘最短路径问题(状态转移方程法)
/// 状态转移方程,也就是迭代递推方式
/// min_dist(i, j) = w[i][j] + min(min_dist(i, j-1), min(min_dist(i-1, j)))
///
/// - Parameter chessboard: 棋盘数据
/// - Returns: 最短路径
func chessboardMinDistDP1(chessboard: [[Int]]) -> Int {
// 状态二维数组,用来存储每个结点的最短路径长度
var states = [[Int]](repeating: [Int](repeating:0 , count: chessboard.count), count: chessboard.count)
// 求解最短路径
return minDistDP(chessboard: chessboard, states: &states, x: chessboard.count-1, y: chessboard.count-1)
}
/// 根据递推公式递归求解最短路径
///
/// - Parameters:
/// - chessboard: 棋盘数据
/// - states: 状态数组
/// - x: 结点x坐标
/// - y: 结点y坐标
/// - Returns: 当前结点的最短路径
private func minDistDP(chessboard: [[Int]], states: inout [[Int]], x: Int, y: Int) -> Int {
// 0,0 直接返回
if x == 0 && y == 0 {
return chessboard[0][0]
}
if states[x][y] > 0 {
return states[x][y]
}
// 求解左边结点的最短路径
var minLeft = Int.max
if y - 1 >= 0 {
minLeft = minDistDP(chessboard: chessboard, states: &states, x: x, y: y-1)
}
// 求解上面结点的最短路径
var minUp = Int.max
if x - 1 >= 0 {
minUp = minDistDP(chessboard: chessboard, states: &states, x: x-1, y: y)
}
let curMinDist = chessboard[x][y] + Swift.min(minLeft, minUp)
states[x][y] = curMinDist
return curMinDist
}
// MARK: - 回溯算法计算
// 最短路径长度
private var minDist = Int.max
/// 回溯算法计算棋盘最短路径长度
///
/// - Parameter chessboard: 棋盘数据
/// - Returns: 返回最短路径长度
func chessboardMinDist(chessboard: [[Int]]) -> Int {
recurMinDist(chessboard: chessboard, x: 0, y: 0, dist: 0)
return minDist
}
/// 递归计算棋盘最短路径长度
///
/// - Parameters:
/// - chessboard: 棋盘数据
/// - x: 棋盘当前结点的横轴坐标,以右上角为原点
/// - y: 棋盘当前结点的纵轴坐标,以右上角为原点
/// - dist: 当前结点的最短路径(不包括当前结点的值)
private func recurMinDist(chessboard: [[Int]], x: Int, y: Int, dist: Int) {
// 到达了棋盘终点,计算最短路径
if x == chessboard.count-1 && y == chessboard.count - 1 {
// 最短路径
let finalDist = dist + chessboard[x][y]
if minDist > finalDist {
minDist = finalDist
return
}
}
// 不能再继续往下走了
if x == chessboard.count || y == chessboard.count {
return
}
// 往右走
if x < chessboard.count {
recurMinDist(chessboard: chessboard, x: x+1, y: y, dist: dist + chessboard[x][y])
}
// 往下走
if y < chessboard.count {
recurMinDist(chessboard: chessboard, x: x, y: y+1, dist: dist + chessboard[x][y])
}
}