题目描述
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];
}
}
}