Skip to content

Commit 4fa3e4d

Browse files
Update
1 parent 259d197 commit 4fa3e4d

11 files changed

+1561
-25
lines changed

problems/0827.最大人工岛.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939

4040
每改变一个0的方格,都需要重新计算一个地图的最大面积,所以 整体时间复杂度为:n^4。
4141

42-
如果对深度优先搜索不了解的录友,可以看这里:[深度优先搜索精讲](https://programmercarl.com/图论深搜理论基础.html)
42+
如果对深度优先搜索不了解的录友,可以看这里:[深度优先搜索精讲](https://programmercarl.com/kamacoder/图论深搜理论基础.html)
4343

4444

4545
## 优化思路

problems/kamacoder/0094.城市间货物运输I-SPFA.md

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,14 @@
88
某国为促进城市间经济交流,决定对货物运输提供补贴。共有 n 个编号为 1 到 n 的城市,通过道路网络连接,网络中的道路仅允许从某个城市单向通行到另一个城市,不能反向通行。
99

1010

11-
网络中的道路都有各自的运输成本和政府补贴,道路的权值计算方式为:运输成本 - 政府补贴。权值为正表示扣除了政府补贴后运输货物仍需支付的费用;权值为负则表示政府的补贴超过了支出的运输成本,实际表现为运输过程中还能赚取一定的收益。
11+
网络中的道路都有各自的运输成本和政府补贴,道路的权值计算方式为:运输成本 - 政府补贴。
1212

13+
权值为正表示扣除了政府补贴后运输货物仍需支付的费用;权值为负则表示政府的补贴超过了支出的运输成本,实际表现为运输过程中还能赚取一定的收益。
1314

14-
请找出从城市 1 到城市 n 的所有可能路径中,综合政府补贴后的最低运输成本。如果最低运输成本是一个负数,它表示在遵循最优路径的情况下,运输过程中反而能够实现盈利。
1515

16+
请找出从城市 1 到城市 n 的所有可能路径中,综合政府补贴后的最低运输成本。
17+
18+
如果最低运输成本是一个负数,它表示在遵循最优路径的情况下,运输过程中反而能够实现盈利。
1619

1720
城市 1 到城市 n 之间可能会出现没有路径的情况,同时保证道路网络中不存在任何负权回路。
1821

@@ -41,11 +44,11 @@
4144
1 3 5
4245
```
4346

44-
## 思路
47+
## 背景
4548

4649
本题我们来系统讲解 Bellman_ford 队列优化算法 ,也叫SPFA算法(Shortest Path Faster Algorithm)。
4750

48-
> SPFA的称呼来自 1994年西南交通大学段凡丁的论文,其实Bellman_ford 提出后不久 (20世纪50年代末期) 就有队列优化的版本,国际上不承认这个算法是是国内提出的。 所以国际上一般称呼 算法为 Bellman_ford 队列优化算法(Queue improved Bellman-Ford)
51+
> SPFA的称呼来自 1994年西南交通大学段凡丁的论文,其实Bellman_ford 提出后不久 (20世纪50年代末期) 就有队列优化的版本,国际上不承认这个算法是是国内提出的。 所以国际上一般称呼 该算法为 Bellman_ford 队列优化算法(Queue improved Bellman-Ford)
4952
5053
大家知道以上来历,知道 SPFA 和 Bellman_ford 队列优化算法 指的都是一个算法就好。
5154

@@ -72,6 +75,8 @@
7275

7376
用队列来记录。(其实用栈也行,对元素顺序没有要求)
7477

78+
## 模拟过程
79+
7580
接下来来举例这个队列是如何工作的。
7681

7782
以示例给出的所有边为例:
@@ -88,27 +93,27 @@
8893

8994
我们依然使用**minDist数组来表达 起点到各个节点的最短距离**,例如minDist[3] = 5 表示起点到达节点3 的最小距离为5
9095

91-
初始化,起点为节点1, 起点到起点的最短距离为0,所以minDist[1] 为 0。 将节点1 加入队列 (下次松弛送节点1开始
96+
初始化,起点为节点1, 起点到起点的最短距离为0,所以minDist[1] 为 0。 将节点1 加入队列 (下次松弛从节点1开始
9297

9398
![](https://code-thinking-1253855093.file.myqcloud.com/pics/20240411115555.png)
9499

95100
------------
96101

97-
从队列里取出节点1,松弛节点1 作为出发点链接的边(节点1 -> 节点2)和边(节点1 -> 节点3)
102+
从队列里取出节点1,松弛节点1 作为出发点连接的边(节点1 -> 节点2)和边(节点1 -> 节点3)
98103

99104
边:节点1 -> 节点2,权值为1 ,minDist[2] > minDist[1] + 1 ,更新 minDist[2] = minDist[1] + 1 = 0 + 1 = 1 。
100105

101106
边:节点1 -> 节点3,权值为5 ,minDist[3] > minDist[1] + 5,更新 minDist[3] = minDist[1] + 5 = 0 + 5 = 5。
102107

103-
将节点2节点3 加入队列,如图:
108+
将节点2节点3 加入队列,如图:
104109

105110
![](https://code-thinking-1253855093.file.myqcloud.com/pics/20240411115544.png)
106111

107112

108113
-----------------
109114

110115

111-
从队列里取出节点2,松弛节点2 作为出发点链接的边(节点2 -> 节点4)和边(节点2 -> 节点5)
116+
从队列里取出节点2,松弛节点2 作为出发点连接的边(节点2 -> 节点4)和边(节点2 -> 节点5)
112117

113118
边:节点2 -> 节点4,权值为1 ,minDist[4] > minDist[2] + (-3) ,更新 minDist[4] = minDist[2] + (-3) = 1 + (-3) = -2 。
114119

@@ -123,7 +128,7 @@
123128
--------------------
124129

125130

126-
从队列里出去节点3,松弛节点3 作为出发点链接的边
131+
从队列里出去节点3,松弛节点3 作为出发点连接的边
127132

128133
因为没有从节点3作为出发点的边,所以这里就从队列里取出节点3就好,不用做其他操作,如图:
129134

@@ -132,11 +137,11 @@
132137

133138
------------
134139

135-
从队列中取出节点4,松弛节点4作为出发点链接的边(节点4 -> 节点6)
140+
从队列中取出节点4,松弛节点4作为出发点连接的边(节点4 -> 节点6)
136141

137142
边:节点4 -> 节点6,权值为4 ,minDist[6] > minDist[4] + 4,更新 minDist[6] = minDist[4] + 4 = -2 + 4 = 2 。
138143

139-
讲节点6加入队列
144+
将节点6加入队列
140145

141146
如图:
142147

@@ -145,7 +150,7 @@
145150

146151
---------------
147152

148-
从队列中取出节点5,松弛节点5作为出发点链接的边(节点5 -> 节点3),边(节点5 -> 节点6)
153+
从队列中取出节点5,松弛节点5作为出发点连接的边(节点5 -> 节点3),边(节点5 -> 节点6)
149154

150155
边:节点5 -> 节点3,权值为1 ,minDist[3] > minDist[5] + 1 ,更新 minDist[3] = minDist[5] + 1 = 3 + 1 = 4
151156

@@ -157,14 +162,14 @@
157162

158163

159164

160-
因为节点3和 节点6 都曾经加入过队列,不用重复加入,避免重复计算。
165+
因为节点3 和 节点6 都曾经加入过队列,不用重复加入,避免重复计算。
161166

162167
在代码中我们可以用一个数组 visited 来记录入过队列的元素,加入过队列的元素,不再重复入队列。
163168

164169

165170
--------------
166171

167-
从队列中取出节点6,松弛节点6 作为出发点链接的边
172+
从队列中取出节点6,松弛节点6 作为出发点连接的边
168173

169174
节点6作为终点,没有可以出发的边。
170175

@@ -181,7 +186,7 @@
181186

182187
了解了大体流程,我们再看代码应该怎么写。
183188

184-
在上面模拟过程中,我们每次都要知道 一个节点作为出发点 链接了哪些节点
189+
在上面模拟过程中,我们每次都要知道 一个节点作为出发点连接了哪些节点
185190

186191
如果想方便知道这些数据,就需要使用邻接表来存储这个图,如果对于邻接表不了解的话,可以看 [kama0047.参会dijkstra堆](./kama0047.参会dijkstra堆.md) 中 图的存储 部分。
187192

@@ -279,7 +284,7 @@ n为其他数值的时候,也是一样的。
279284
280285
并没有计算 出队列 和 入队列的时间消耗。 因为这个在不同语言上 时间消耗也是不一定的。
281286
282-
以C++为例,以下两端代码理论上,时间复杂度都是 O(n) :
287+
以C++为例,以下两段代码理论上,时间复杂度都是 O(n) :
283288
284289
```CPP
285290
for (long long i = 0; i < n; i++) {
@@ -316,7 +321,7 @@ SPFA(队列优化版Bellman_ford) 在理论上 时间复杂度更胜一筹
316321

317322
这里可能有录友疑惑,`while (!que.empty())` 队里里 会不会造成死循环? 例如 图中有环,这样一直有元素加入到队列里?
318323

319-
其实有环的情况,要看它是 正权回路 还是 负全回路
324+
其实有环的情况,要看它是 正权回路 还是 负权回路
320325

321326
题目描述中,已经说了,本题没有 负权回路 。
322327

problems/kamacoder/0099.岛屿的数量广搜.md

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -54,14 +54,16 @@
5454

5555
这道题题目是 DFS,BFS,并查集,基础题目。
5656

57-
本题思路,是用遇到一个没有遍历过的节点陆地,计数器就加一,然后把该节点陆地所能遍历到的陆地都标记上。
57+
本题思路:遇到一个没有遍历过的节点陆地,计数器就加一,然后把该节点陆地所能遍历到的陆地都标记上。
5858

59-
在遇到标记过的陆地节点和海洋节点的时候直接跳过。 这样计数器就是最终岛屿的数量。
59+
再遇到标记过的陆地节点和海洋节点的时候直接跳过。 这样计数器就是最终岛屿的数量。
6060

6161
那么如果把节点陆地所能遍历到的陆地都标记上呢,就可以使用 DFS,BFS或者并查集。
6262

6363
### 广度优先搜索
6464

65+
如果不熟悉广搜,建议先看 [广搜理论基础](./图论广搜理论基础.md)
66+
6567
不少同学用广搜做这道题目的时候,超时了。 这里有一个广搜中很重要的细节:
6668

6769
根本原因是**只要 加入队列就代表 走过,就需要标记,而不是从队列拿出来的时候再去标记走过**
@@ -72,7 +74,7 @@
7274

7375
![图二](https://code-thinking-1253855093.file.myqcloud.com/pics/20220727100846.png)
7476

75-
超时写法 (从队列中取出节点再标记)
77+
超时写法 (从队列中取出节点再标记,注意代码注释的地方
7678

7779
```CPP
7880
int dir[4][2] = {0, 1, 1, 0, -1, 0, 0, -1}; // 四个方向
@@ -98,7 +100,7 @@ void bfs(vector<vector<char>>& grid, vector<vector<bool>>& visited, int x, int y
98100
```
99101

100102

101-
加入队列 就代表走过,立刻标记,正确写法:
103+
加入队列 就代表走过,立刻标记,正确写法: (注意代码注释的地方)
102104

103105
```CPP
104106
int dir[4][2] = {0, 1, 1, 0, -1, 0, 0, -1}; // 四个方向
@@ -155,7 +157,6 @@ void bfs(const vector<vector<int>>& grid, vector<vector<bool>>& visited, int x,
155157
}
156158
}
157159

158-
159160
int main() {
160161
int n, m;
161162
cin >> n >> m;

0 commit comments

Comments
 (0)