LeetCode847 访问所有结点的最短路径

Posted So istes immer

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LeetCode847 访问所有结点的最短路径相关的知识,希望对你有一定的参考价值。

题目
给出 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]

示例什么意思呢?
每一个维度的数据表示第i个节点可到的其他节点,如[[1],[0,2,4],[1,3,4],[2],[1,2]]表示:节点0可以到节点1,节点1可以到0,2,4;节点2可以到1,3,4;节点3可以到2;节点4可以到1,2

思路:BFS

class State {
    int cover, head;
    State(int c, int h) {
        cover = c;
        head = h;
    }
}

cover 表示当前已经访问过的所有节点
head 表示当前节点
如何用cover当前已经访问过的所有节点?
状态压缩
每个节点的“未遍历”与“已遍历”可以用0/1表示
如果 cover 的第 k 个比特位是 1,表示该路径经过了第 k 个节点

定义一个二维数组dist
dist[i][j],i对应 State里的cover,j对应 State里的head
i和j两个变量一起表示了一种状态,能够表示已经遍历了哪些节点
dist[i][j]里面存放的则是:在目前这种状态下的最短路径

N个结点,一共2N种状态,所以数组要有2N
代码:int[][] dist = new int[1<<N][N];

BFS需要用到队列:Queue queue = new LinkedList();
//结点入队并对dist数组做初始化

for (int[] row: dist) Arrays.fill(row, N*N);
        for (int x = 0; x < N; ++x) {
            queue.offer(new State(1<<x, x));
            dist[1 << x][x] = 0;
        }

BFS过程

while (!queue.isEmpty()) {
            State node = queue.poll();				//从队列中取出一个状态State
            int d = dist[node.cover][node.head];		//取出当前状态下的最短路径
            if (node.cover == (1<<N) - 1) return d;	//如果当前的State中的cover化成二进制后全是1,也就是说已经遍历完所有节点了,返回当前状态下的最短路径
            for (int child: graph[node.head]) {                //遍历当前节点的邻接点
                int cover2 = node.cover | (1 << child);	 //如果能找到一条新路径
                if (d + 1 < dist[cover2][child]) {  //并且相同状态下,当前路径的长度,比之前找到的路径还短(相同状态下可能不止一条路径,dist存放同一状态路径最短值)
                    dist[cover2][child] = d + 1;			 //更新dist[i][j]的值
                    queue.offer(new State(cover2, child));//新路径所表示的状态State入队
                }
            }
        }

整体代码

class Solution {
    public int shortestPathLength(int[][] graph) {
        int N = graph.length;
        Queue<State> queue = new LinkedList();
        int[][] dist = new int[1<<N][N];
        for (int[] row: dist) Arrays.fill(row, N*N);

        for (int x = 0; x < N; ++x) {
            queue.offer(new State(1<<x, x));
            dist[1 << x][x] = 0;
        }

        while (!queue.isEmpty()) {
            State node = queue.poll();
            int d = dist[node.cover][node.head];
            if (node.cover == (1<<N) - 1) return d;

            for (int child: graph[node.head]) {
                int cover2 = node.cover | (1 << child);
                if (d + 1 < dist[cover2][child]) {
                    dist[cover2][child] = d + 1;
                    queue.offer(new State(cover2, child));
                }
            }
        }
        throw null;
    }
}

以上是关于LeetCode847 访问所有结点的最短路径的主要内容,如果未能解决你的问题,请参考以下文章

LeetCode 847 访问所有节点的最短路径[BFS] HERODING的LeetCode之路

⭐算法入门⭐《动态规划 - 状态压缩DP》困难01 —— LeetCode 847. 访问所有节点的最短路径

LeetCode802. 找到最终的安全状态(图论三色标记法拓扑排序)/847. 访问所有节点的最短路径(特殊的bfs,状态压缩,dp)

LeetCode练习目录

leetcode 847. Shortest Path Visiting All Nodes 无向连通图遍历最短路径

访问所有节点的最短路径