最短路径求算

来源:互联网 发布:黑苹果mac os安装教程 编辑:程序博客网 时间:2024/05/21 19:24

算法概述

Dijkstra 算法用于求算单源点最短路径问题,即给定源点,求算该点到其他各点的最短距离。
源点到任意点的最短路径建立在源点到该点前驱的最短路径上。以源点为中心,向外一步一步扩展,直到所有点的最短路径都被找出。
此外,该算法要求任意两点间的权值不可为负值。

情景

这里写图片描述

思路

一开始,我打算先实现Dijkstra 算法,所以直接将图的邻接矩阵、前驱数组这些设为全局变量(二维数组的传参我给忘了),而且将邻接矩阵直接初始化,减少调试的成本。

设源点为V0,求算V0到各终点的最短距离。

这里写图片描述

初始化最短距离数组(Distance)、前驱数组(Pioneer)、状态数组(S);
Dijikstra 算法核心:
1.从当前点开始更新最短距离数组(如果当前点是源点则不用更新,因为已经在初始化方法中更新了);
2.找出最短距离数组中权值最小的结点,并认为该点为已找到;
3.以该点作为当前点,回到第一步。
打印路径和最短距离;

代码一

#include<stdio.h>#include<stdlib.h>#define N 6     //记录图中点的数量#define MAX 1000#define START 0     //起点/*邻接矩阵寝室 0; 偏门 1; A广场 2; 大门 3; B广场 4; A 5;点与点间有临接路径,则值为两点间权值;点与点间没有临接路径,或为同点,则值为MAX;*/float Graph[N][N] = {    { MAX,200,MAX,250,MAX,MAX },    { MAX,MAX,MAX,150,MAX,MAX },    { MAX,50,MAX,MAX,MAX,250 },    { MAX,MAX,MAX,MAX,60,MAX },    { MAX,MAX,300,MAX,MAX,MAX },    { MAX,MAX,250,MAX,350,MAX }};/*记录最短距离例如 V0 -> V2 -> V4 存在最短路径, 且V0 -> V2 = 20, V2 -> V4 = 40,则 Distance[4] = 60;Distance 数组元素初始化为START 行的数据;Distance[START] = 0;*/float Distance[N];/*记录前驱例如 V0 -> V2 -> V4 ,则Pioneer[4] = 2;Pioneer数组元素初始化全为 -1;Pioneer[起点] 永为 -1,  起点到起点没前驱;*/int Pioneer[N];/*记录起点与该点之间是否已找到最短路径;找到: 1, 没找到: 0;S 数组元素除起点外全部初始化为 0;S[起点]   永为 1;*/int S[N];/*************************************************//*初始化 Distance、Pioneer、S 数组*/void initialize() {    //初始化Distance 数组    for (int i = 0;i < N;i++) {        Distance[i] = Graph[START][i];    }    Distance[START] = 0;    //初始化Previous 数组    for (int i = 0;i < N;i++) {        if (Distance[i] != 0 && Distance[i] != MAX) {            Pioneer[i] = START;        }        else {            Pioneer[i] = -1;        }    }    //初始化S 数组    for (int i = 0;i < N;i++) {        S[i] = 0;    }    S[START] = 1;   //S[起点] 永为 1}/*迪吉斯特算法核心*/void Dijkstra() {    int minV;    float minDis = MAX;    int curV = START;    int count = 0;    while (++count < N) {        if (curV == START) {        }        else if (curV != START) {            for (int i = 0;i < N;i++) {                if (Graph[curV][i] != MAX && S[i] != 1) {                    if (Distance[i] > Graph[curV][i] + Distance[curV]) {                        Distance[i] = Graph[curV][i] + Distance[curV];                        Pioneer[i] = curV;                    }                }            }   //end for        }        for (int i = 0;i < N;i++) {            if (Distance[i] < minDis && S[i] != 1) {                minV = i;                minDis = Distance[i];            }        }   //end for        S[minV] = 1;        //刷新        curV = minV;        minDis = MAX;    }    //end while}/*打印路径*/void printPath() {    //用于临时存放路径信息,帮助打印    //Path 数组元素默认值全为 -1;    int Path[N];    //刷新Path 数组    for (int i = 0;i < N;i++) {        Path[i] = -1;    }    //记录Path 的写入位置    //默认指向Path 数组的最后一个元素    int count = N - 1;    int preV;    int curV;    int midian; //临时存放结点    for (int i = 0;i < N;i++) {        count = N - 1;        //排除起点        if (i == START) {            continue;        }        Path[count--] = i;  //终点        preV = Pioneer[i];        while (preV != -1) {            Path[count--] = preV;            curV = preV;            preV = Pioneer[curV];        }        count++;        //打印路径        printf("%d -> %d 路径 : ", START, i);        if (Distance[i] != MAX) {            for (int j = count;j < N;j++) {                printf("%d ", Path[j]);            }            printf("\n最短距离%6.2f", Distance[i]);        }        else {            printf("\n不存在此路径");        }        printf("\n");    }}/************************************************************/int main(){    initialize();    Dijkstra();    printPath();    system("pause");    return 0;}

代码二

修改之后,我将图邻接矩阵的初始化交由用户来处理,程序自动检测图的大小。

#include<stdio.h>#include<stdlib.h>#define SIZE 10         //记录图中点数量的最大值   #define MAX 1000#define START 0     //起点/*************************************************//*初始化图*/int InputGraph(float Graph[][SIZE]) {    int cmd = 0;    int VA;    int VB;    ///test    int maxSize = 0;    for (int i = 0;i < SIZE;i++) {        for (int j = 0;j < SIZE;j++) {            Graph[i][j] = MAX;        }    }    puts("请输入指令    1:添加路径,0:退出");    scanf(" %d", &cmd);    while (cmd != 0) {        puts("请输入起点和终点,用空格分隔:");        scanf("%d %d", &VA, &VB);        if (VA >= SIZE || VB >= SIZE) {            puts("数组溢出");        }        else {            if (maxSize < VA) {                maxSize = VA;            }            else if (maxSize < VB) {                maxSize = VB;            }            puts("请输入两点间的距离:");            scanf("%f", &Graph[VA][VB]);            if (Graph[VA][VB] < 0) {                puts("错误距离");            }        }        puts("请输入指令    1:添加路径,0:退出");        scanf(" %d", &cmd);    }    maxSize++;    return maxSize;}/*初始化 Distance、Pioneer、S 数组*/void initialize(float Graph[][SIZE], float Distance[], float Pioneer[], int S[], const int N) {    //初始化Distance 数组    for (int i = 0;i < N;i++) {        Distance[i] = Graph[START][i];    }    Distance[START] = 0;    //初始化Pioneer 数组    for (int i = 0;i < N;i++) {        if (Distance[i] != 0 && Distance[i] != MAX) {            Pioneer[i] = START;        }        else {            Pioneer[i] = -1;        }    }    //初始化S 数组    for (int i = 0;i < N;i++) {        S[i] = 0;    }    S[START] = 1;   //S[起点] 永为 1}/*迪吉斯特算法核心*/void Dijkstra(float Graph[][SIZE], float Distance[], float Pioneer[], int S[], const int N) {    int minV;    float minDis = MAX;    int curV = START;    int count = 0;    while (++count < N) {        if (curV == START) {        }        else if (curV != START) {            for (int i = 0;i < N;i++) {                if (Graph[curV][i] != MAX && S[i] != 1) {                    if (Distance[i] > Graph[curV][i] + Distance[curV]) {                        Distance[i] = Graph[curV][i] + Distance[curV];                        Pioneer[i] = curV;                    }                }            }   //end for        }        for (int i = 0;i < N;i++) {            if (Distance[i] < minDis && S[i] != 1) {                minV = i;                minDis = Distance[i];            }        }   //end for        S[minV] = 1;        //刷新        curV = minV;        minDis = MAX;    }}/*打印路径*/void printPath(float Distance[], float Pioneer[],const int N) {    //用于临时存放路径信息,帮助打印    //Path 数组元素默认值全为 -1;    int Path[SIZE];    //刷新Path 数组    for (int i = 0;i < N;i++) {        Path[i] = -1;    }    //记录Path 的写入位置    //默认指向Path 数组的最后一个元素    int count = N - 1;    int preV;    int curV;    int midian; //临时存放结点    for (int i = 0;i < N;i++) {        count = N - 1;        //排除起点        if (i == START) {            continue;        }        Path[count--] = i;  //终点        preV = Pioneer[i];        while (preV != -1) {            Path[count--] = preV;            curV = preV;            preV = Pioneer[curV];        }        count++;        //打印路径        printf("%d -> %d 路径 : ", START, i);        if (Distance[i] != MAX) {            for (int j = count;j < N;j++) {                printf("%d ", Path[j]);            }            printf("\n最短距离%6.2f", Distance[i]);        }        else {            printf("\n不存在此路径");        }        printf("\n");    }}/************************************************************/int main(){    /*        邻接矩阵        寝室 0; 偏门 1; A广场 2; 大门 3; B广场 4; A 5;        点与点间有临接路径,则值为两点间权值;        点与点间没有临接路径,或为同点,则值为MAX;    */    float Graph[SIZE][SIZE];    /*        记录最短距离        例如 V0 -> V2 -> V4 存在最短路径, 且V0 -> V2 = 20, V2 -> V4 = 40,        则 Distance[4] = 60;        Distance 数组元素初始化为START 行的数据;        Distance[START] = 0;    */    float Distance[SIZE];    /*        记录前驱        例如 V0 -> V2 -> V4 ,则Pioneer[4] = 2;        Pioneer 数组元素初始化全为 -1;        Pioneer[起点] 永为 -1,  起点到起点没前驱;    */    int Pioneer[SIZE];    /*        记录起点与该点之间是否已找到最短路径;        找到: 1, 没找到: 0;        S 数组元素除起点外全部初始化为 0;        S[起点]   永为 1;    */    int S[SIZE];    const int N = InputGraph(Graph);    initialize(Graph, Distance, Pioneer, S,N);    Dijkstra(Graph, Distance, Pioneer, S, N);    printPath(Distance, Pioneer, N);    system("pause");    return 0;}

调试结果

这里写图片描述
这里写图片描述

最后,打印路径的那一部分程序可用递归函数的方式来处理,程序会更加简明。这个程序就先写到这儿吧,偷个懒。

原创粉丝点击