最短路径

本文介绍了一种使用Dijkstra算法解决单源最短路径问题的方法,并针对大数值的情况自定义了bigInteger类来处理高精度计算。通过邻接链表结构实现了算法流程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最短路径


题目来源:
最短路径

这里写图片描述

思路分析

  • 由于是单源最短路径问题,所以采用Dijkstra算法
  • 由于题目中距离很大,超出整数表示范围,所以自定义bigInteger,用于保存高精度整数。

代码


#include <stdio.h>
#include <vector>

using namespace std;

struct bigInteger{        //定义高精度整数,用于保存距离
    int digit[1001];
    int size;
    void init(){
        for(int i=0; i<1001; i++){
            digit[i] = 0;
        }
        size = 0;
    }

    void set(int x){
        init();
        if(x==-1){             //当距离为-1表示两点之间没有直接通路
            digit[0] = -1;
            size = 1;
        }
        else{
            do{
                digit[size++] = x%10000;
                x = x/10000;
            }while(x!=0);
        }
    }

    bigInteger operator * (int x) const{
        int carry = 0;
        bigInteger ret;
        ret.init();
        for(int i=0; i<size; i++){
            ret.digit[ret.size++] = (digit[i]*x+carry)%10000;
            carry = (digit[i]*x+carry)/10000;
        }
        if(carry!=0){
            ret.digit[ret.size++] = carry;
        }
        return ret;
    }

    bigInteger operator + (const bigInteger A)const{
        bigInteger ret;
        ret.init();
        int carry = 0;
        for(int i=0; i<size||i<A.size; i++){
            ret.digit[ret.size++] = (digit[i]+A.digit[i]+carry)%10000;
            carry = (digit[i]+A.digit[i]+carry)/10000;
        }
        if(carry!=0){
            ret.digit[ret.size++] = carry;
        }
        return ret;
    }



    int operator % (int x) const{
        int remain = 0;
        for(int i=size-1; i>=0; i--){
            int temp = remain*10000+digit[i];
            remain = temp%x;
        }
        return remain;
    }

    bool operator < (const bigInteger A) const{
        if(size<A.size) return size<A.size;
        else{
            for(int i=size-1; i>=0; i--){
                if(digit[i]!=A.digit[i])
                    return digit[i]<A.digit[i];
            }
            return digit[0]<A.digit[0];
        }
    }

}cost[501];


struct E{            //用于存储邻接链表的节点
    int next;        //与节点相邻的节点编号
    bigInteger c;    //与节点相邻的节点next和本节点之间的权值
};

vector<E> edge[501];   //邻接链表
bool mark[101];        //标记,当mark[j]为true时,表示结点j的最短路径长度已经得到,该结点已经加入集合k;
bigInteger dist[101];  //距离向量,当mark[i]为true时,表示已得的最短路径长度;否则,表示所有从开始结点出发,经过已知的最短路径达到集合k中的某结点,再经过一条边到达结点i的路径中最短的距离。


int main(int argc, const char * argv[]) {

    int M,N;
    while (scanf("%d%d", &N, &M)!=EOF){
        for (int i=0; i<501; i++) {
            edge[i].clear();

        }
        for (int i=0; i<101; i++) {
            dist[i].init();
            dist[i].set(-1);
            mark[i] = false;
        }

        cost[0].set(1);
        cost[1].set(2);
        for(int i=0; i<M; i++){
            int a,b;
            scanf("%d%d", &a, &b);
            if (i>1) {
                cost[i] = cost[i-1]*2;
            }
            E temp;
            temp.next = b;
            temp.c = cost[i];
            edge[a].push_back(temp);
            temp.next = a;
            edge[b].push_back(temp);
        }
        mark[0] = true;
        int newP = 0;   //集合中新加入的点为0;
        dist[0].set(0);
        for(int j = 1; j<N; j++){
            for(int i=0; i<edge[newP].size(); i++){
                int t = edge[newP][i].next;       //与新加入的结点相邻的结点
                bigInteger cc = edge[newP][i].c;  //与新加入的结点相邻结点的权值
                if (mark[t]==true) {              //如果与新加入的结点相邻的结点已经在集合k,则跳过
                    continue;
                }
                bigInteger temp;
                temp = dist[newP]+cc;
                if(dist[t].digit[0]==-1||temp<dist[t])  //如果与新加入的结点相邻的结点之前不可达,或者通过新加入的结点到达的距离更短,则更新距离
                    dist[t] = temp;
            }
            bigInteger min;
            min.size = 1001;
            for (int i=0; i<1001; i++) {      //最小值初始化为一个大整数,为找最小值做准备
                min.digit[i] = 9999;
            }

            for (int i=1; i<=N; i++) {         //遍历所有结点,找到还未放入集合k,且距离最小的结点设置为newP
                if (mark[i]==true||dist[i].digit[0]==-1) {
                    continue;
                }
                if (dist[i]<min) {
                    min = dist[i];
                    newP = i;
                }
            }
            mark[newP] = true;    //把newP放入集合k
        }
        for (int i=1; i<N; i++) {          //按照题目输出到所有结点的距离
            printf("%d\n", dist[i]%100000);
        }
    }

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值