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)
}

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);
}

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;
}

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;
}

2023-05-12:存在一个由 n 个节点组成的无向连通图,图中的节点按从 0 到 n - 1 编号, 给你一个数组 graph 表示这个图, 其中,graph[i] 是一个列表,由所有与节点 i的更多相关文章

  1. Graph Neural Network——图神经网络

    本文是跟着李沐老师的论文精度系列进行GNN的学习的,详细链接请见:零基础多图详解图神经网络(GNN/GCN)[论文精读] 该论文的标题为<A Gentle Introduction to Gra ...

  2. 给定一个double类型的数组arr,其中的元素可正可负可0,返回子数组累乘的最大乘积。例如arr=[-2.5,4,0,3,0.5,8,-1],子数组[3,0.5,8]累乘可以获得最大的乘积12,所以返回12。

    分析,是一个dp的题目, 设f[i]表示以i为结尾的最大值,g[i]表示以i结尾的最小值,那么 f[i+1] = max{f[i]*arr[i+1], g[i]*arr[i+1],arr[i+1]} ...

  3. Ex 3_25 图中每个顶点有一个相关价格..._十一次作业

    (a)首先对有向无环图进行拓扑排序,再按拓扑排序的逆序依次计算每个顶点的cost值,每个顶点的cost值为自身的price值与相邻顶点间的cost值得最小值 (b)求出图中的每一个强连通分量,并把所有 ...

  4. 从上面的集合框架图可以看到,Java 集合框架主要包括两种类型的容器,一种是集合(Collection),存储一个元素集合,另一种是图(Map),存储键/值对映射

    从上面的集合框架图可以看到,Java 集合框架主要包括两种类型的容器,一种是集合(Collection),存储一个元素集合,另一种是图(Map),存储键/值对映射.Collection 接口又有 3 ...

  5. 设计一个算法,採用BFS方式输出图G中从顶点u到v的最短路径(不带权的无向连通图G採用邻接表存储)

    思想:图G是不带权的无向连通图.一条边的长度计为1,因此,求带顶点u和顶点v的最短的路径即求顶点u和顶点v的边数最少的顶点序列.利用广度优先遍历算法,从u出发进行广度遍历,类似于从顶点u出发一层一层地 ...

  6. Paddle Graph Learning (PGL)图学习之图游走类模型[系列四]

    Paddle Graph Learning (PGL)图学习之图游走类模型[系列四] 更多详情参考:Paddle Graph Learning 图学习之图游走类模型[系列四] https://aist ...

  7. 图像分割之(二)Graph Cut(图割)

    zouxy09@qq.com http://blog.csdn.net/zouxy09 上一文对主要的分割方法做了一个概述.那下面我们对其中几个比较感兴趣的算法做个学习.下面主要是Graph Cut, ...

  8. graph使泳道图的label横向显示

    1.如果需要将label靠左边对齐,则必须重写底层源码 新增mxText的一个构造器,主要是增加了一个参数:x(代表当前的cell) function mxText(a, b, c, d, e, f, ...

  9. [LeetCode] 882. Reachable Nodes In Subdivided Graph 细分图中的可到达结点

    Starting with an undirected graph (the "original graph") with nodes from 0 to N-1, subdivi ...

  10. sql 根据指定条件获取一个字段批量获取数据插入另外一张表字段中+MD5加密

    /****** Object: StoredProcedure [dbo].[getSplitValue] Script Date: 03/13/2014 13:58:12 ******/ SET A ...

随机推荐

  1. 1.java基本语法

    一.数据和数据类型 (一)标识符:给变量.常量.方法类.对象等命名的符号 (二)变量和常量 1.变量:值在运行时可以改变的量: 每个变量属于特定的数据类型,使用前要先声明,然后赋值,初始化或赋值后才能 ...

  2. STM32定时器(TIM1、TIM2、TIM3、TIM4、TIM5、TIM8)高级定时器+普通定时器,配置使用

    2.1    时钟来源 计数器时钟可以由下列时钟源提供: ·内部时钟(CK_INT) ·外部时钟模式1:外部输入脚(TIx) ·外部时钟模式2:外部触发输入(ETR) ·内部触发输入(ITRx):使用 ...

  3. 【项目实战】SpringBoot+uniapp+uview2打造一个企业黑红名单吐槽小程序

    logo 避坑宝 v1.0.0 基于SpringBoot+uniapp企业黑红名单吐槽小程序 项目介绍 避坑宝 [避坑宝]企业黑红名单吐槽小程序是一个具有吐槽发布企业信息的一个平台,言论自由,评判自定 ...

  4. 基于 Agora SDK 实现 Windows 端的一对一视频通话(基于3.6.2版本)

    前提条件 Microsoft Visual Studio 2019 或以上版本 支持 Windows 7 或以上版本的 Windows 设备 有效的 Agora 账户(免费注册) 注:如果你的网络环境 ...

  5. 如何基于 React Native 快速实现一个视频通话应用

    今天,我们将会一起开发一个包含 RTE (实时互动)场景的 Flutter 应用. 项目介绍 靠自研开发包含实时互动功能的应用非常繁琐,你要解决维护服务器.负载均衡等难题,同时还要保证稳定的低延迟. ...

  6. SQL server分页的三种方法

    一.Entity Framework的Linq语句的分页写法: var datacount = test.OrderBy(t => t.testID) .Skip(pageSize * (pag ...

  7. 2020寒假学习笔记14------Python基础语法学习(三)

    今天学习了Python的基础语法,其中学的内容有: 比较运算符.逻辑运算符.同一运算符.整数缓存问题.基本运算符.复合复制运算符.运算符优先级问题.字符串基本特点.字符串的编码.空字符串和len()函 ...

  8. python入门教程之一 什么是python

    python简介 1 什么是python Python是一种计算机程序设计语言.你可能已经听说过很多种流行的编程语言,比如非常难学的C语言,非常流行的Java语言,适合初学者的Basic语言,适合网页 ...

  9. 部署:windows7下mysql8.0.18部署安装

    一.前期准备(windows7+mysql-8.0.18-winx64) 1.下载地址:https://dev.mysql.com/downloads/ 2.选择直接下载不登录账号,下载的压缩包大概两 ...

  10. Springboot接入ChatGPT 续

    在之前的文章\(^{[ 1 ]}\)中,原方案的设计,是基于功能实现的角度去设计的,对于功能性的拓展,考虑不全面,结合收到的反馈意见,对项目进行了拓展优化.完成的优化拓展有如下几个方面 固定会话 历史 ...