2023-05-12:存在一個由 n 個節點組成的無向連通圖,圖中的節點按從 0 到 n - 1 編號,
給你一個數組 graph 表示這個圖,
其中,graph[i] 是一個列表,由所有與節點 i 直接相連的節點組成。
返回能夠訪問所有節點的最短路徑的長度。
你可以在任一節點開始和停止,也可以多次重訪節點,并且可以重用邊。
輸入:graph = [[1,2,3],[0],[0],[0]]。
輸出:4。
答案2023-05-12:
大體步驟如下:
1.首先,在 main 函數中調用 shortestPathLength 函數,并將圖的鄰接表 graph 作為參數傳入。
2.在 shortestPathLength 函數中,獲取圖中節點的個數 n,使用 Floyd 算法計算所有節點之間的最短路徑距離,并將結果保存到 distance 二維數組中,同時初始化一個 ans 變量為整型最大值。
3.接下來,初始化一個 dp 數組,其中 dp[i][j] 表示當前狀態為 i(二進制表示),當前在節點 j 的情況下,能形成的最短路徑長度。同時,對于 dp 數組進行初始化,將所有元素的值設為 -1。
4.循環遍歷每個節點 i,從 i 節點出發,通過 process 函數求出訪問所有節點的最短路徑長度,并更新 ans 的值。
5.在 process 函數中,首先判斷當前狀態是否已經訪問了所有節點,如果是,返回 0 表示已經完成訪問。如果 dp 數組中已有對應狀態和當前節點的最短路徑長度,則直接返回該值,避免重復計算。
6 如果上述條件都不滿足,則遍歷所有未訪問過的且與當前節點 cur 相鄰的節點 next,對于這些節點,遞歸調用 process 函數,并記錄訪問當前節點 cur 和下一個節點 next 所需的距離 distance[cur][next],然后將其加上遞歸得到的 nextAns 值,更新 ans 的值。
7.最后,將計算出的最短路徑長度 ans 保存到 dp 數組中,并返回該值。在主函數中輸出 ans 的值即為能夠訪問所有節點的最短路徑的長度。
時間復雜度:本算法中使用了 Floyd 算法計算所有節點之間的最短路徑,其時間復雜度為 O(n^3);同時,使用動態規劃求解當前狀態下訪問所有節點的最短路徑長度,需要遍歷狀態空間和鄰接表,時間復雜度為 O(2^n * n^2)。因此,總的時間復雜度為 O(n^3 + 2^n * n^2)。
空間復雜度:本算法中使用了一個距離矩陣 distance 數組來存儲節點之間的最短路徑距離,其空間復雜度為 O(n^2);同時,使用了一個 dp 數組來記錄狀態和節點的最短路徑長度,其空間復雜度也是 O(2^n * n)。因此,總的空間復雜度為 O(n^2 + 2^n * n)。
go語言完整代碼如下:
package main
import (
"fmt"
"math"
)
func shortestPathLength(graph [][]int) int {
n := len(graph)
distance := floyd(n, graph)
ans := math.MaxInt32
dp := make([][]int, 1<<n)
for i := 0; i < (1 << n); i++ {
dp[i] = make([]int, n)
for j := 0; j < n; j++ {
dp[i][j] = -1
}
}
for i := 0; i < n; i++ {
ans = min(ans, process(1<<i, i, n, distance, dp))
}
return ans
}
func floyd(n int, graph [][]int) [][]int {
distance := make([][]int, n)
for i := 0; i < n; i++ {
distance[i] = make([]int, n)
for j := 0; j < n; j++ {
distance[i][j] = math.MaxInt32
}
}
for i := 0; i < n; i++ {
distance[i][i] = 0
}
for cur := 0; cur < n; cur++ {
for _, next := range graph[cur] {
distance[cur][next] = 1
distance[next][cur] = 1
}
}
for jump := 0; jump < n; jump++ {
for from := 0; from < n; from++ {
for to := 0; to < n; to++ {
if distance[from][jump] != math.MaxInt32 && distance[jump][to] != math.MaxInt32 &&
distance[from][to] > distance[from][jump]+distance[jump][to] {
distance[from][to] = distance[from][jump] + distance[jump][to]
}
}
}
}
return distance
}
func process(status, cur, n int, distance, dp [][]int) int {
if status == (1<<n)-1 {
return 0
}
if dp[status][cur] != -1 {
return dp[status][cur]
}
ans := math.MaxInt32
for next := 0; next < n; next++ {
if status&(1<<next) == 0 && distance[cur][next] != math.MaxInt32 {
nextAns := process(status|(1<<next), next, n, distance, dp)
if nextAns != math.MaxInt32 {
ans = min(ans, distance[cur][next]+nextAns)
}
}
}
dp[status][cur] = ans
return ans
}
func min(a, b int) int {
if a < b {
return a
}
return b
}
func main() {
graph := [][]int{{1, 2, 3}, {0}, {0}, {0}}
ans := shortestPathLength(graph)
fmt.Println(ans)
}
[圖片上傳失敗...(image-faf2ad-1683900706599)]
rust語言完整代碼如下:
fn shortest_path_length(graph: Vec<Vec<i32>>) -> i32 {
let n = graph.len();
let distance = floyd(n, &graph);
let mut ans = std::i32::MAX;
let mut dp = vec![vec![-1; n]; 1 << n];
for i in 0..(1 << n) {
for j in 0..n {
dp[i][j] = -1;
}
}
for i in 0..n {
ans = ans.min(process(1 << i, i, n, &distance, &mut dp));
}
return ans;
}
fn floyd(n: usize, graph: &Vec<Vec<i32>>) -> Vec<Vec<i32>> {
let mut distance = vec![vec![std::i32::MAX; n]; n];
// 初始化認為都沒路
for i in 0..n {
for j in 0..n {
distance[i][j] = std::i32::MAX;
}
}
// 自己到自己的距離為0
for i in 0..n {
distance[i][i] = 0;
}
// 支持任意有向圖,把直接邊先填入
for cur in 0..n {
for &next in graph[cur].iter() {
distance[cur][next as usize] = 1;
distance[next as usize][cur] = 1;
}
}
// O(N^3)的過程
// 枚舉每個跳板
// 注意! 跳板要最先枚舉,然后是from和to
for jump in 0..n {
for from in 0..n {
for to in 0..n {
if distance[from][jump] != std::i32::MAX
&& distance[jump][to] != std::i32::MAX
&& distance[from][to] > distance[from][jump] + distance[jump][to]
{
distance[from][to] = distance[from][jump] + distance[jump][to];
}
}
}
}
return distance;
}
// status : 所有已經走過點的狀態
// 0 1 2 3 4 5
// int
// 5 4 3 2 1 0
// 0 0 1 1 0 1
// cur : 當前所在哪個城市!
// n : 一共有幾座城
// 返回值 : 從此時開始,逛掉所有的城市,至少還要走的路,返回!
fn process(
status: i32,
cur: usize,
n: usize,
distance: &Vec<Vec<i32>>,
dp: &mut Vec<Vec<i32>>,
) -> i32 {
// 5 4 3 2 1 0
// 1 1 1 1 1 1
// 1 << 6 - 1
if status == (1 << n) - 1 {
return 0;
}
if dp[status as usize][cur] != -1 {
return dp[status as usize][cur];
}
let mut ans = std::i32::MAX;
// status:
// 5 4 3 2 1 0
// 0 0 1 0 1 1
// cur : 0
// next : 2 4 5
for next in 0..n {
if (status & (1 << next)) == 0 && distance[cur][next] != std::i32::MAX {
let next_ans = process(status | (1 << next), next, n, distance, dp);
if next_ans != std::i32::MAX {
ans = ans.min(distance[cur][next] + next_ans);
}
}
}
dp[status as usize][cur] = ans;
return ans;
}
fn main() {
let graph = vec![vec![1, 2, 3], vec![0], vec![0], vec![0]];
let ans = shortest_path_length(graph);
println!("{}", ans);
}
[圖片上傳失敗...(image-b047be-1683900706599)]
c語言完整代碼如下:
#include <iostream>
#include <vector>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 15, INF = 0x3f3f3f3f;
int n;
int dist[N][N], dp[1 << N][N];
int floyd(vector<vector<int>>& graph)
{
n = graph.size();
memset(dist, 0x3f, sizeof dist);
for (int i = 0; i < n; i++)
for (auto j : graph[i])
dist[i][j] = 1;
for (int k = 0; k < n; k++)
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j]);
return 0;
}
int dfs(int status, int cur)
{
if (status == (1 << n) - 1)
return 0;
if (dp[status][cur] != -1)
return dp[status][cur];
int ans = INF;
for (int next = 0; next < n; next++)
if ((status & (1 << next)) == 0 && dist[cur][next] != INF)
{
int nextAns = dfs(status | (1 << next), next);
if (nextAns != INF)
ans = min(ans, dist[cur][next] + nextAns);
}
return dp[status][cur] = ans;
}
int shortestPathLength(vector<vector<int>>& graph) {
memset(dp, -1, sizeof dp);
floyd(graph);
int ans = INF;
for (int i = 0; i < n; i++)
ans = min(ans, dfs(1 << i, i));
return ans;
}
int main()
{
vector<vector<int>> graph = { {1,2,3},{0},{0},{0} };
cout << shortestPathLength(graph) << endl;
return 0;
}
[圖片上傳失敗...(image-b03aa-1683900706599)]
c++語言完整代碼如下:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define N 15
#define INF 0x3f3f3f3f
int n;
int dist[N][N], dp[1 << N][N];
void floyd(int** graph, int graphSize, int* graphColSize)
{
n = graphSize;
memset(dist, 0x3f, sizeof dist);
for (int i = 0; i < n; i++)
for (int j = 0; j < graphColSize[i]; j++)
dist[i][graph[i][j]] = 1;
for (int k = 0; k < n; k++)
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
dist[i][j] = dist[i][j] < dist[i][k] + dist[k][j] ? dist[i][j] : dist[i][k] + dist[k][j];
}
int dfs(int status, int cur)
{
if (status == (1 << n) - 1)
return 0;
if (dp[status][cur] != -1)
return dp[status][cur];
int ans = INF;
for (int next = 0; next < n; next++)
if ((status & (1 << next)) == 0 && dist[cur][next] != INF)
{
int nextAns = dfs(status | (1 << next), next);
if (nextAns != INF)
ans = ans < dist[cur][next] + nextAns ? ans : dist[cur][next] + nextAns;
}
return dp[status][cur] = ans;
}
int shortestPathLength(int** graph, int graphSize, int* graphColSize) {
memset(dp, -1, sizeof dp);
floyd(graph, graphSize, graphColSize);
int ans = INF;
for (int i = 0; i < n; i++)
ans = ans < dfs(1 << i, i) ? ans : dfs(1 << i, i);
return ans;
}
int main()
{
int graphSize = 4;
int graphColSize[] = { 3, 1, 1, 1 };
int** graph = (int**)malloc(sizeof(int*) * graphSize);
for (int i = 0; i < graphSize; i++)
{
graph[i] = (int*)malloc(sizeof(int) * graphColSize[i]);
memcpy(graph[i], (int[]) { 0 }, sizeof(int)* graphColSize[i]);
}
graph[0][0] = 1;
graph[0][1] = 2;
graph[0][2] = 3;
printf("%d\n", shortestPathLength(graph, graphSize, graphColSize));
for (int i = 0; i < graphSize; i++)
free(graph[i]);
free(graph);
return 0;
}
[圖片上傳失敗...(image-1ba791-1683900706599)]