JAVA程序设计:访问所有节点的最短路径(LeetCode:847)

给出 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

方法一:广搜最短路。

因为N只有12这么大, 我们可以考虑用二进制表示状态,其中若二进制表示中第i位为1表示编号为i的点在所走的路径中已经访问过,既然状态能够正确表示,剩下的就是最短路板子题了。

class Solution {
	
	class node{
		int head,cover;
		public node(int head,int cover) {
			this.head=head;
			this.cover=cover;
		}
	}
	
    public int shortestPathLength(int[][] graph) {
    	
    	int n=graph.length;
    	int[][] dis=new int[1<<n][n];
    	Queue<node> q=new LinkedList<>();
    	for(int[] dist : dis) Arrays.fill(dist, n*n);
    	
    	for(int i=0;i<n;i++) {
    		q.add(new node(i,1<<i));
    		dis[1<<i][i]=0;
    	}
    	
    	while(!q.isEmpty()) {
    		node now=q.poll();
    		int d=dis[now.cover][now.head];
    		if(now.cover==(1<<n)-1) return d;
    		
    		for(int child : graph[now.head]) {
    			int nowCover=now.cover|(1<<child);
    			if(d+1<dis[nowCover][child]) {
    				dis[nowCover][child]=d+1;
    				q.add(new node(child,nowCover));
    			}
    		}
    	}
    	
    	return -1;
    }
}

方法二:动态规划(参考官方题解

该方法大致思路和方法一相同,我们仍然用dis[cover][head]表示到head节点并且路径状态为cover的最短路径,每个状态其实是一个DAG(有向无环图),对于这类图,我们往往可以用动态规划解决。

对于每个head节点,下一个可能的next节点来自于与head直接相连的点集,在每次添加新节点时,如果 dist[cover2][next] > dist[cover][head] + 1,则更新路径长度 dist[cover2][next] = dist[cover][head] + 1,如果 cover = cover2,则需要在同一 cover 上再次执行松弛法,重新更新最短路径。

在每次cover迭代的过程中,产生的新状态cover2都满足cover2>=cover,因此这也是拓扑排序,所有路径形成了DAG。

class Solution {	
    public int shortestPathLength(int[][] graph) {
    	
    	int n=graph.length;
    	int[][] dis=new int[1<<n][n];
    	for(int[] dist : dis) Arrays.fill(dist, n*n);
    	
    	for(int i=0;i<n;i++)
    		dis[1<<i][i]=0;
    	
    	for(int cover=0;cover<(1<<n);cover++) {
    		boolean flag=true;
    		while(flag) {
    			flag=false;
    			for(int head=0;head<n;head++) {
    				int d=dis[cover][head];
    				for(int next : graph[head]) {
    					int cover2=cover|(1<<next);
    					if(d+1<dis[cover2][next]) {
    						dis[cover2][next]=d+1;
    						if(cover2==cover) 
    							flag=true;
    					}
    				}
    			}
    		}
    	}
    	
    	int ans=n*n;
    	for(int val : dis[(1<<n)-1])
    		ans=Math.min(ans, val);
    	
    	return ans;
    }
}
原创文章 1111 获赞 194 访问量 25万+

猜你喜欢

转载自blog.csdn.net/haut_ykc/article/details/105504165