※上海交通大学 最短路径(java)(生成树+解法巧妙)

题目描述
N个城市,标号从0到N-1,M条道路,第K条道路(K从0开始)的长度为2^K,求编号为0的城市到其他城市的最短距离
输入描述:
第一行两个正整数N(2<=N<=100)M(M<=500),表示有N个城市,M条道路
接下来M行两个整数,表示相连的两个城市的编号
输出描述:
N-1行,表示0号城市到其他城市的最短路,如果无法到达,输出-1,数值太大的以MOD 100000 的结果输出。
示例1
输入
复制
4 4
1 2
2 3
1 3
0 1
输出
复制
8
9
11

最小生成树

注意到第k条路径的长度为2^K,则第k条路径的长度会大于前k-1条路径的总和。
由此我们可知两个推断:
(1)在添加第k条路径时,如果路径k连接的两个城市A 、B已经通过其他路径间接的连通了,那么第k条路径绝对不是AB间的最短路径(第k条路径之后的路径也不可能有比当前AB路径更短的路径了,因为第k条路径的长度会大于前k-1条路径的总和)
(2)在添加第k条路径时,如果路径k连接的两个城市A 、B是第一次被连通了(也就是说此前没有任何路径能连通AB,包括通过多条路径间接连通),那么路径k就是AB之间的最短距离了,因为以后不可能存在更短的路径连接AB,以后的单条路径只会越来越长。
通过上述的推断,我们可以利通过建立一个最小连通树的同时算出0号城市到各个城市的最小路径。
具体的算法:
(1)构造一个并查集,每个城市指向自己,二维数组d记录城市之间的距离,初始化为-1不可达,d[i][i]初始化为0
(2)取第一条路径,第一条路径连接了城市a、b,城市a、b间最短路径就是第一条路径,然后把a、b合并在一个集合里
(3)再取一条路径,
(一)如果这条边连接的城市c、d,已经在同一个集合里了(即已经联通了),那么当前的路径一定不是cd之间的最短路径了,忽略之(理由是推断(1)),继续看下一条路径。
  (二)如果这条路径连接的城市c、d不在同一个集合里(之前没有联通过),很好,这条路径是cd之间的最短路径(理由是推断(2));除此之外我们还可以看看通过这条路径能不能让c集合里的城市到d集合里的城市之间的路径更短呢?即是不是d[i][j]>(d[i][C]+dist+d[D][j]) ?(注意i和C一个集合,D和j一个集合),如果是的话可以更新一下这个值。
(4)重复(3)直到所有路径都处理过了
0号城市到各个城市i的最小路径结果就是d[0][i]了
import java.util.*;
import java.io.*;
import java.text.* ;
public class Main
{
	public static HashMap<String, Integer> mon = new HashMap<>();
    public static void main(String[] args) throws ParseException{
    	try {
	        BufferedReader br= new BufferedReader(new InputStreamReader(System.in));
	        String str;
	        while((str = br.readLine()) != null) {
	        	String[] parts = str.split(" ");
	        	int n = Integer.parseInt(parts[0]);
	        	int len = Integer.parseInt(parts[1]);
	        	int[][] dis = new int[n][n];
	        	int[] tree = new int[n];
	        	int[] lens = new int[len];
	        	lens[0] = 1;
	        	int i;
	        	for(i = 0; i < n; i++) {
	        		tree[i] = -1;
	        		for(int j = 0; j < n; j++) dis[i][j] = -1;
	        		dis[i][i] = 0;
	        	}
	        	int x, y;
	        	for(i = 0; i < len; i++) {
	        		parts = br.readLine().split(" ");
	        		int a = Integer.parseInt(parts[0]);
	        		int b = Integer.parseInt(parts[1]);
	        		x = findRoot(a, tree);
	        		y = findRoot(b, tree);
        			if(i>0){
                        lens[i] = (lens[i-1]*2)%100000;
                    }
	        		if(x != y) {
	        			for(int j = 0; j < n; j++) {
	        				if(x == findRoot(j, tree)) {
	        					for(int k = 0; k < n; k++) {	        						
	        						if(y == findRoot(k, tree))
	        							dis[j][k]=(dis[j][a]+dis[b][k]+lens[i])%100000;
	        							dis[k][j]=dis[j][k];
	        					}
	        				}
	        			}
	        			tree[y] = x;
	        		}
	        	}
	        	x = findRoot(0, tree);
	        	for(i = 1; i < n; i++)
	        		System.out.println(dis[0][i]);
	        }
 	    } catch (IOException e) {
	        e.printStackTrace();
	    }
    }
    public static int findRoot(int x, int[] tree) {
    	if(tree[x] == -1) return x;
    	else {
    		tree[x] = findRoot(tree[x], tree);
    		return tree[x];
    	}
    }
}

发布了231 篇原创文章 · 获赞 22 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_43306331/article/details/104193151