Leetcode 847. 访问所有节点的最短路径

该博客介绍了如何解决一个关于无向连通图的问题,目标是找到访问所有节点的最短路径。使用广度优先搜索(BFS)结合状态压缩的策略,通过维护一个队列存储节点信息,包括节点、已访问节点的状态和路径长度。每次从队列中取出节点,更新已访问状态并检查是否达到所有节点都已访问的情况。当找到一条满足条件的最短路径时,返回其长度。博客中还给出了具体的C++实现代码,并讨论了时间复杂度和空间复杂度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

存在一个由 n 个节点组成的无向连通图,图中的节点按从 0 到 n - 1 编号。

给你一个数组 graph 表示这个图。其中,graph[i] 是一个列表,由所有与节点 i 直接相连的节点组成。

返回能够访问所有节点的最短路径的长度。你可以在任一节点开始和停止,也可以多次重访节点,并且可以重用边。

示例 1:

输入:graph = [[1,2,3],[0],[0],[0]]
输出:4
解释:一种可能的路径为 [1,0,2,0,3]
示例 2:

 输入:graph = [[1],[0,2,4],[1,3,4],[2],[1,2]]
输出:4
解释:一种可能的路径为 [0,1,4,2,3]
 

提示:

n == graph.length
1 <= n <= 12
0 <= graph[i].length < n
graph[i] 不包含 i
如果 graph[a] 包含 b ,那么 graph[b] 也包含 a
输入的图总是连通图

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/shortest-path-visiting-all-nodes
 

解法

bfs+状态压缩。本题我是真的想不到可以这么做,看了官方题解后才自己去编写代码,其实思路还是好理解的。本题是无向图,且边的权重是1,求最短路径,所以可以用bfs。常规的bfs中队列存储的是节点的编号,本题要求的是经过全部节点的最短路径(本以为用最小生成树算法呢),所以还需存储已经经过的节点。最终用三元组(u, mask, dist)来存储信息:

1.u表示当前节点

2.mask是一个n为二进制数,表示经过了哪些节点,其中第i位为1,则表示第i个节点已经被搜索过。

3.dist表示遍历到节点u并且已经遍历过的节点状态为mask时,走过的距离。

同时需要保证每个节点u以及搜过情况mask只被搜索一次,所以需要一个二维数组state,state[u][mask]=true表示节点u以及搜过情况mask已经搜索过了。

class Solution {
public:
	int shortestPathLength(vector<vector<int>>& graph) {
		queue<tuple<int, int, int>> q;      //tuple(u, mask, dist)表示搜索到节点u时,已经经过了的点的状态为mask,
                                            //走过的距离为dist,其中mask是长度为n的二进制数,第i位为1,表示节点i
                                            //已经遍历过
		int n = graph.size();
		if (n == 1)
			return 0;
		int top = 1 << n;
		vector<vector<bool>> state(n, vector<bool>(top));   //state[u][mask]=true, 表示遍历到u节点时,
                                                            //已经遍历过的节点状态为mask
		for (int i = 0; i < n; ++i)
		{
			q.push(make_tuple(i, 1 << i, 0));                //可以从任一节点开始,初始入队所有节点
			state[i][1 << i] = true;
		}
		int ans = 0;
		bool flag = false;
		while (!q.empty())
		{
			int u, mask, dist;
			tie( u, mask, dist) = q.front(); //或者用auto [u, mask, dist]=q.front()
			q.pop();
			for (auto &v : graph[u])
			{
				int mask_v = mask | (1 << v);
				if (!state[v][mask_v])
				{
					state[v][mask_v] = true;
					q.push(make_tuple(v, mask_v, dist + 1));
					if (mask_v == top - 1)    //终止状态
					{ 
						ans = dist+1;
						flag = true;
						break;
					}
				}
			}
			if (flag)
				break;
		}
		return ans;
	}
};

本题的时间复杂度为O(n^{2}2^{n}),空间复杂对O(n2^{n})

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值