最短路径

https://github.com/ultraji

/*
问题 最短路径

题目描述
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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值