问题:
给定一个图,graph[i]代表节点 i 相连的各个节点。
求遍历完所有节点,所需要的最小路径花费。
⚠️ 注意:可以重复经过同一条边or同一个节点。
Example 1: Input: [[1,2,3],[0],[0],[0]] Output: 4 Explanation: One possible path is [1,0,2,0,3] Example 2: Input: [[1],[0,2,4],[1,3,4],[2],[1,2]] Output: 4 Explanation: One possible path is [0,1,4,2,3] Note: 1 <= graph.length <= 12 0 <= graph[i].length < graph.length
解法:BFS
状态:(我们要找到不能重复操作的状态)
- 1.当前遍历过的节点->mask(bit)
- 2.当前位于哪个节点(遍历后的最后一个节点)
若重复上述两条件后的同一个状态,进行check的话,会出现循环冗余。
因此我们将上述两个条件合并,作为一个状态Node,作为queue的一个元素。
同时【条件2】对于queue的展开,进行下一个状态的确定有关,因此必不可少。
对于重复状态的判断,我们用unordered_set,
由于set的重复判断特性,简单起见,我们将状态Node转化为现存的string,省略实现==的操作。
而最后所要求的遍历最小路径花费,即为queue展开层数。
从0层开始,最先找到 target 状态所花费的层数,则为最小路径花费。
这里,target状态对应于【条件1】的mask为:(1<<graph.size) -1
代码参考:
1 class Node { 2 public: 3 int mask;//state:1 4 int v;//state:2 5 Node(int a, int b) { 6 mask = a; 7 v = b; 8 } 9 string tostring() { 10 return to_string(mask)+to_string(v); 11 } 12 }; 13 14 class Solution { 15 public: 16 int shortestPathLength(vector<vector<int>>& graph) { 17 //state: 18 //1.node which has been visited 19 //2.node which is the last one to be visited -> to get next node 20 //if this state duplicated, we should not check again. 21 //we choose Node as cell of queue. 22 int n = graph.size(); 23 queue<Node> q; 24 unordered_set<string> visited;//for = operation, we use string(existing structure) 25 int level = 0; 26 //target mask: ((1<<n)-1) 27 int target_mask = (1<<n)-1; 28 //start mask: 29 for(int i=0; i<n; i++) { 30 Node cur(1<<i, i); 31 q.push(cur); 32 visited.insert(cur.tostring()); 33 } 34 //traverse queue 35 while(!q.empty()) { 36 int sz = q.size(); 37 for(int i=0; i<sz; i++) { 38 Node cur = q.front(); 39 q.pop(); 40 if(cur.mask==target_mask) return level; 41 for(auto nextn:graph[cur.v]) { 42 Node nt(cur.mask|(1<<nextn), nextn); 43 if(visited.insert(nt.tostring()).second) { 44 q.push(nt); 45 } 46 } 47 } 48 level++; 49 } 50 return -1; 51 } 52 };