/*
问题 最短路径
题目描述
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 的结果输出。
样例输入
4 3
0 1
1 2
2 0
样例输出
1
3
-1
*/
//根据边加入的权值可知,越晚加入的边的权值越大;
//而且由 1+2^1+2^2 ... + 2^(n-1) < 2^n 可知:
// 若两点都已经在同一集合中时,新加入的边不可能成为最短路径。
//可以根据并查集判断这条边的两点是否在同一集合,若不是,则加入该边;
//从而得到一个邻接矩阵,存有最小生成树
#include <iostream>
#include <queue>
using namespace std;
const int maxn = 101,INF = 100000;
int d[maxn]; //最短路径
int mp[maxn]; //访问表
int v[maxn][maxn]; //邻接矩阵
int Father[maxn]; //并查集
int dp_pow[520]; //pow(2,n)%100000
int mypow(int n){//动态规划 pow(2,n)%100000
if(n == 0) dp_pow[n] = 1;
if(dp_pow[n] == 0) dp_pow[n] = mypow(n-1)*2 % INF;
return dp_pow[n];
}
void init(){//初始化并查集,访问表,最短路径数组,邻接矩阵
for(int i = 0; i < maxn; i++){
Father[i] = i;
mp[i] = 0;
d[i] = -1;
}
for(int i = 0; i < maxn; i++)
for(int j = i; j < maxn; j++)
v[i][j] = 0;
}
//并查集操作
int findFather(int a){
while(a !=Father[a]) a = Father[a];
return a;
}
void Union(int a,int b){
int fa = findFather(a);
int fb = findFather(b);
if(fa != fb) Father[fa] = fb;
}
//从顶点p开始层序遍历访问各个顶点,计算最短路径
void cal_shortPath(int p,int n){
queue<int> q;
q.push(p);
d[p] = 0;
mp[p] = 1;
while(!q.empty()){
p = q.front(); q.pop();
for(int i = 0; i < n; i++){
if(v[p][i] != 0 && mp[i] != 1){
q.push(i);
mp[i] = 1; //为了防止访问完v[a][b],再次访问v[b][a]
d[i] = ( d[p] + v[p][i] )% INF;
}
}
}
}
int main(){
int a,b,n,m;
while(cin >> n >> m){
init();
for(int i = 0; i < m; i++){
cin >> a >> b;
if(findFather(a) != findFather(b)){ //将不是同一集合的两点加入,并加入这条边
v[a][b] = mypow(i);
v[b][a] = v[a][b];
Union(a,b);
}
}
cal_shortPath(0,n); //从顶点p开始层序遍历访问各个顶点
for(int i = 1; i < n; i++) cout << d[i] << endl;
}
return 0;
}
最短路径
最新推荐文章于 2023-03-29 20:38:46 发布