Skip to content

Commit cde6d1e

Browse files
committed
feat: add solutions to lc problem: No.0847
No.0847.Shortest Path Visiting All Nodes
1 parent 1788ebe commit cde6d1e

File tree

3 files changed

+344
-1
lines changed

3 files changed

+344
-1
lines changed

solution/0800-0899/0847.Shortest Path Visiting All Nodes/README.md

Lines changed: 163 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,17 @@
4343

4444
<!-- 这里可写通用的实现逻辑 -->
4545

46-
因为每条边权值一样,所以用 BFS 就能得出最短路径,过程中可以用状态压缩记录节点的访问情况
46+
因为每条边权值一样,所以用 BFS 就能得出最短路径,过程中可以用**状态压缩**记录节点的访问情况。另外,同一个节点 u 以及对应的节点访问情况需要保证只被搜索过一次,因此可以用 `vis(u, state)` 表示是否已经被搜索过,防止无效的重复搜索。
47+
48+
本题也属于 BFS 最小步数模型,可以使用 A\* 算法优化搜索。
49+
50+
A\* 算法主要思想如下:
51+
52+
1. 将 BFS 队列转换为优先队列(小根堆);
53+
1. 队列中的每个元素为 `(dist[state] + f(state), state)``dist[state]` 表示从起点到当前 state 的距离,`f(state)` 表示从当前 state 到终点的估计距离,这两个距离之和作为堆排序的依据;
54+
1. 当终点第一次出队时,说明找到了从起点到终点的最短路径,直接返回对应的 step;
55+
1. `f(state)` 是估价函数,并且估价函数要满足 `f(state) <= g(state)`,其中 `g(state)` 表示 state 到终点的真实距离;
56+
1. A\* 算法只能保证终点第一次出队时,即找到了一条从起点到终点的最小路径,不能保证其他点出队时也是从起点到当前点的最短路径。
4757

4858
<!-- tabs:start -->
4959

@@ -75,6 +85,33 @@ class Solution:
7585
return 0
7686
```
7787

88+
A\* 算法:
89+
90+
```python
91+
class Solution:
92+
def shortestPathLength(self, graph: List[List[int]]) -> int:
93+
n = len(graph)
94+
95+
def f(state):
96+
return sum(((state >> i) & 1) == 0 for i in range(n))
97+
98+
q = []
99+
dist = [[float('inf')] * (1 << n) for _ in range(n)]
100+
for i in range(n):
101+
heapq.heappush(q, (f(1 << i), i, 1 << i))
102+
dist[i][1 << i] = 0
103+
while q:
104+
_, u, state = heapq.heappop(q)
105+
if state == (1 << n) - 1:
106+
return dist[u][state]
107+
for v in graph[u]:
108+
nxt = state | (1 << v)
109+
if dist[v][nxt] > dist[u][state] + 1:
110+
dist[v][nxt] = dist[u][state] + 1
111+
heapq.heappush(q, (dist[v][nxt] + f(nxt), v, nxt))
112+
return 0
113+
```
114+
78115
### **Java**
79116

80117
<!-- 这里可写当前语言的特殊实现逻辑 -->
@@ -123,6 +160,53 @@ class Solution {
123160
}
124161
```
125162

163+
A\* 算法:
164+
165+
```java
166+
class Solution {
167+
private int n;
168+
169+
public int shortestPathLength(int[][] graph) {
170+
n = graph.length;
171+
int[][] dist = new int[n][1 << n];
172+
for (int i = 0; i < n; ++i) {
173+
Arrays.fill(dist[i], Integer.MAX_VALUE);
174+
}
175+
PriorityQueue<int[]> q = new PriorityQueue<>(Comparator.comparingInt(a -> a[0]));
176+
for (int i = 0; i < n; ++i)
177+
{
178+
q.offer(new int[]{f(1 << i), i, 1 << i});
179+
dist[i][1 << i] = 0;
180+
}
181+
while (!q.isEmpty()) {
182+
int[] p = q.poll();
183+
int u = p[1], state = p[2];
184+
if (state == (1 << n) - 1) {
185+
return dist[u][state];
186+
}
187+
for (int v : graph[u]) {
188+
int nxt = state | (1 << v);
189+
if (dist[v][nxt] > dist[u][state] + 1) {
190+
dist[v][nxt] = dist[u][state] + 1;
191+
q.offer(new int[]{dist[v][nxt] + f(nxt), v, nxt});
192+
}
193+
}
194+
}
195+
return 0;
196+
}
197+
198+
private int f(int state) {
199+
int ans = 0;
200+
for (int i = 0; i < n; ++i) {
201+
if (((state >> i) & 1) == 0) {
202+
++ans;
203+
}
204+
}
205+
return ans;
206+
}
207+
}
208+
```
209+
126210
### **Go**
127211

128212
```go
@@ -163,6 +247,84 @@ func shortestPathLength(graph [][]int) int {
163247
}
164248
```
165249

250+
### **C++**
251+
252+
```cpp
253+
class Solution {
254+
public:
255+
int shortestPathLength(vector<vector<int>>& graph) {
256+
int n = graph.size();
257+
queue<tuple<int, int, int>> q;
258+
vector<vector<bool>> vis(n, vector<bool>(1 << n));
259+
for (int i = 0; i < n; ++i)
260+
{
261+
q.emplace(i, 1 << i, 0);
262+
vis[i][1 << i] = true;
263+
}
264+
while (!q.empty())
265+
{
266+
auto [u, state, dist] = q.front();
267+
q.pop();
268+
if (state == (1 << n) - 1) return dist;
269+
for (int& v : graph[u])
270+
{
271+
int nxt = state | (1 << v);
272+
if (!vis[v][nxt])
273+
{
274+
q.emplace(v, nxt, dist + 1);
275+
vis[v][nxt] = true;
276+
}
277+
}
278+
}
279+
return 0;
280+
}
281+
};
282+
```
283+
284+
A\* 算法:
285+
286+
```cpp
287+
class Solution {
288+
public:
289+
int n;
290+
291+
int shortestPathLength(vector<vector<int>>& graph) {
292+
n = graph.size();
293+
priority_queue<tuple<int, int, int>, vector<tuple<int, int, int>>, greater<tuple<int, int, int>>> q;
294+
vector<vector<int>> dist(n, vector<int>(1 << n, INT_MAX));
295+
for (int i = 0; i < n; ++i)
296+
{
297+
q.push({f(1 << i), i, 1 << i});
298+
dist[i][1 << i] = 0;
299+
}
300+
while (!q.empty())
301+
{
302+
auto [_, u, state] = q.top();
303+
q.pop();
304+
if (state == (1 << n) - 1) return dist[u][state];
305+
for (int v : graph[u])
306+
{
307+
int nxt = state | (1 << v);
308+
if (dist[v][nxt] > dist[u][state] + 1)
309+
{
310+
dist[v][nxt] = dist[u][state] + 1;
311+
q.push({dist[v][nxt] + f(nxt), v, nxt});
312+
}
313+
}
314+
}
315+
return 0;
316+
}
317+
318+
int f(int state) {
319+
int ans = 0;
320+
for (int i = 0; i < n; ++i)
321+
if (((state >> i) & 1) == 0)
322+
++ans;
323+
return ans;
324+
}
325+
};
326+
```
327+
166328
### **...**
167329

168330
```

solution/0800-0899/0847.Shortest Path Visiting All Nodes/README_EN.md

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,33 @@ class Solution:
7979
return 0
8080
```
8181

82+
A\* search:
83+
84+
```python
85+
class Solution:
86+
def shortestPathLength(self, graph: List[List[int]]) -> int:
87+
n = len(graph)
88+
89+
def f(state):
90+
return sum(((state >> i) & 1) == 0 for i in range(n))
91+
92+
q = []
93+
dist = [[float('inf')] * (1 << n) for _ in range(n)]
94+
for i in range(n):
95+
heapq.heappush(q, (f(1 << i), i, 1 << i))
96+
dist[i][1 << i] = 0
97+
while q:
98+
_, u, state = heapq.heappop(q)
99+
if state == (1 << n) - 1:
100+
return dist[u][state]
101+
for v in graph[u]:
102+
nxt = state | (1 << v)
103+
if dist[v][nxt] > dist[u][state] + 1:
104+
dist[v][nxt] = dist[u][state] + 1
105+
heapq.heappush(q, (dist[v][nxt] + f(nxt), v, nxt))
106+
return 0
107+
```
108+
82109
### **Java**
83110

84111
```java
@@ -125,6 +152,53 @@ class Solution {
125152
}
126153
```
127154

155+
A\* search:
156+
157+
```java
158+
class Solution {
159+
private int n;
160+
161+
public int shortestPathLength(int[][] graph) {
162+
n = graph.length;
163+
int[][] dist = new int[n][1 << n];
164+
for (int i = 0; i < n; ++i) {
165+
Arrays.fill(dist[i], Integer.MAX_VALUE);
166+
}
167+
PriorityQueue<int[]> q = new PriorityQueue<>(Comparator.comparingInt(a -> a[0]));
168+
for (int i = 0; i < n; ++i)
169+
{
170+
q.offer(new int[]{f(1 << i), i, 1 << i});
171+
dist[i][1 << i] = 0;
172+
}
173+
while (!q.isEmpty()) {
174+
int[] p = q.poll();
175+
int u = p[1], state = p[2];
176+
if (state == (1 << n) - 1) {
177+
return dist[u][state];
178+
}
179+
for (int v : graph[u]) {
180+
int nxt = state | (1 << v);
181+
if (dist[v][nxt] > dist[u][state] + 1) {
182+
dist[v][nxt] = dist[u][state] + 1;
183+
q.offer(new int[]{dist[v][nxt] + f(nxt), v, nxt});
184+
}
185+
}
186+
}
187+
return 0;
188+
}
189+
190+
private int f(int state) {
191+
int ans = 0;
192+
for (int i = 0; i < n; ++i) {
193+
if (((state >> i) & 1) == 0) {
194+
++ans;
195+
}
196+
}
197+
return ans;
198+
}
199+
}
200+
```
201+
128202
### **Go**
129203

130204
```go
@@ -165,6 +239,84 @@ func shortestPathLength(graph [][]int) int {
165239
}
166240
```
167241

242+
### **C++**
243+
244+
```cpp
245+
class Solution {
246+
public:
247+
int shortestPathLength(vector<vector<int>>& graph) {
248+
int n = graph.size();
249+
queue<tuple<int, int, int>> q;
250+
vector<vector<bool>> vis(n, vector<bool>(1 << n));
251+
for (int i = 0; i < n; ++i)
252+
{
253+
q.emplace(i, 1 << i, 0);
254+
vis[i][1 << i] = true;
255+
}
256+
while (!q.empty())
257+
{
258+
auto [u, state, dist] = q.front();
259+
q.pop();
260+
if (state == (1 << n) - 1) return dist;
261+
for (int& v : graph[u])
262+
{
263+
int nxt = state | (1 << v);
264+
if (!vis[v][nxt])
265+
{
266+
q.emplace(v, nxt, dist + 1);
267+
vis[v][nxt] = true;
268+
}
269+
}
270+
}
271+
return 0;
272+
}
273+
};
274+
```
275+
276+
A\* search:
277+
278+
```cpp
279+
class Solution {
280+
public:
281+
int n;
282+
283+
int shortestPathLength(vector<vector<int>>& graph) {
284+
n = graph.size();
285+
priority_queue<tuple<int, int, int>, vector<tuple<int, int, int>>, greater<tuple<int, int, int>>> q;
286+
vector<vector<int>> dist(n, vector<int>(1 << n, INT_MAX));
287+
for (int i = 0; i < n; ++i)
288+
{
289+
q.push({f(1 << i), i, 1 << i});
290+
dist[i][1 << i] = 0;
291+
}
292+
while (!q.empty())
293+
{
294+
auto [_, u, state] = q.top();
295+
q.pop();
296+
if (state == (1 << n) - 1) return dist[u][state];
297+
for (int v : graph[u])
298+
{
299+
int nxt = state | (1 << v);
300+
if (dist[v][nxt] > dist[u][state] + 1)
301+
{
302+
dist[v][nxt] = dist[u][state] + 1;
303+
q.push({dist[v][nxt] + f(nxt), v, nxt});
304+
}
305+
}
306+
}
307+
return 0;
308+
}
309+
310+
int f(int state) {
311+
int ans = 0;
312+
for (int i = 0; i < n; ++i)
313+
if (((state >> i) & 1) == 0)
314+
++ans;
315+
return ans;
316+
}
317+
};
318+
```
319+
168320
### **...**
169321

170322
```
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
class Solution {
2+
public:
3+
int shortestPathLength(vector<vector<int>>& graph) {
4+
int n = graph.size();
5+
queue<tuple<int, int, int>> q;
6+
vector<vector<bool>> vis(n, vector<bool>(1 << n));
7+
for (int i = 0; i < n; ++i)
8+
{
9+
q.emplace(i, 1 << i, 0);
10+
vis[i][1 << i] = true;
11+
}
12+
while (!q.empty())
13+
{
14+
auto [u, state, dist] = q.front();
15+
q.pop();
16+
if (state == (1 << n) - 1) return dist;
17+
for (int& v : graph[u])
18+
{
19+
int nxt = state | (1 << v);
20+
if (!vis[v][nxt])
21+
{
22+
q.emplace(v, nxt, dist + 1);
23+
vis[v][nxt] = true;
24+
}
25+
}
26+
}
27+
return 0;
28+
}
29+
};

0 commit comments

Comments
 (0)