给出 graph 为有 N 个节点(编号为 0, 1, 2, …, N-1)的无向连通图。
graph.length = N,且只有节点 i 和 j 连通时,j != i 在列表 graph[i] 中恰好出现一次。
返回能够访问所有节点的最短路径的长度。你可以在任一节点开始和停止,也可以多次重访节点,并且可以重用边。
示例 1:
输入:[[1,2,3],[0],[0],[0]]
输出:4
解释:一个可能的路径为 [1,0,2,0,3]
示例 2:
输入:[[1],[0,2,4],[1,3,4],[2],[1,2]]
输出:4
解释:一个可能的路径为 [0,1,4,2,3]
提示:
1 <= graph.length <= 12
0 <= graph[i].length < graph.length
首先这道题的“最短路径”并不是指路径中各条边的和的最小值,而是指路径中出现的边的条数最少。因此我们要找到一条路径,这条路径中边的条数最少,并且经过了所有点。其中graph是邻接表,graph[i]代表它能到达的点集合,graph[i][j]代表节点i、j之间有边。并且题干中说明美个点、每条边可以经过多次。
那么这道题比较关键的地方就是如何记录一条路径中已经访问过的点,由于1 <= graph.length <= 12,所以我们可以使用一个比特位来记录点的访问,比如“011001”表示访问了第0、3、4这三个点,1 << i表示访问了第i个节点。
class Solution {
public:
int shortestPathLength(vector<vector<int>>& graph) {
int graphSize = graph.size(), minSteps = 0;//minSteps存储最短路径
int allVisited = (1 << graphSize) - 1;//当所有节点都访问了的时候,第graphSize - 1到第0位都是1的状态
//booked[i][state]记录在访问到节点i并且经过的路径状态为state这个情况是否到达过(用于剪枝)
vector<vector<int>> booked(graphSize, vector<int>(allVisited + 1, 0));
queue<pair<int, int>> myQue;//{i, state}i为现在所处的节点,state为到达i经过的路径状态
for (int i = 0; i < graphSize; ++i){
myQue.push({i, 1 << i});//初始化所有起点以及对应的状态
}
while (!myQue.empty()){
//每次都将当前队列中的所有状态都向后移动一步
for (int i = myQue.size(); i > 0; --i){
pair<int, int> front = myQue.front();
myQue.pop();
if (allVisited == front.second){//已经访问过所有点
return minSteps;
}
//将front.first这个位置转移到它能到达的位置
for (auto &next : graph[front.first]){
int next_state = front.second | (1 << next);//访问next这个点更新后的路径状态
if (!booked[next][next_state]){//如果这个状态没有标记过
booked[next][next_state] = 1;//标记
myQue.push({next, next_state});//放入队列
}
}
}
++minSteps;//路边的条数自增
}
return minSteps;
}
};
来源:CSDN
作者:hestyle
链接:https://blog.csdn.net/qq_41855420/article/details/90736398