迪杰斯特拉算法代码实现及分析 6-2 最短路径(迪杰斯特拉算法)

试实现迪杰斯特拉最短路径算法。

函数接口定义:
void ShortestPath_DIJ(AMGraph G, int v0);
其中 G 是基于邻接矩阵存储表示的有向图, v0表示源点

裁判测试程序样例:

#include <iostream>
using namespace std;

#define MaxInt 32767
#define MVNum 100 
typedef char VerTexType;
typedef int ArcType;

int *D=new int[MVNum];
bool *S=new bool[MVNum];
int *Path=new int[MVNum];

typedef struct{ 
    VerTexType vexs[MVNum]; 
    ArcType arcs[MVNum][MVNum]; 
    int vexnum,arcnum;
}AMGraph;

void CreateUDN(AMGraph &G){ 
    int i , j , k;
    cin >> G.vexnum >> G.arcnum;

    for(i = 0; i < G.vexnum; ++i){   
        cin >> G.vexs[i];       
    }

    for(i = 0; i < G.vexnum; ++i)            
        for(j = 0; j < G.vexnum; ++j)   
            G.arcs[i][j] = MaxInt;  

    for(k = 0; k < G.arcnum;++k){                            
        VerTexType v1 , v2;
        ArcType w;
        cin >> v1 >> v2 >> w;                                
        i = LocateVex(G, v1);  
        j = LocateVex(G, v2);        
        G.arcs[i][j] = w;                                    
        G.arcs[j][i] = G.arcs[i][j];                         
    }
}

void ShortestPath_DIJ(AMGraph G, int v0);

void DisplayPath(AMGraph G , int begin ,int temp ){
    if(Path[temp] != -1){
        DisplayPath(G , begin ,Path[temp]);
        cout << G.vexs[Path[temp]] << "->";
    }
}

int main()
{
    AMGraph G; 
    int i , j ,num_start , num_destination;
    VerTexType start , destination;
    CreateUDN(G);
    cin >> start >> destination;
    num_start = LocateVex(G , start);
    num_destination = LocateVex(G , destination);
    ShortestPath_DIJ(G , num_start);
    DisplayPath(G , num_start , num_destination);
    cout << G.vexs[num_destination]<<endl;
    return 0;
}
/* 请在这里填写答案 */

输入样例:
第1行输入结点数vexnum和边数arcnum。第2行输入vexnum个字符表示结点的值,接下来依次输入arcnum行,每行输入3个值,前两个字符表示结点,后一个数表示两个结点之间边的权值。最后一行输入源点及终点。

6 8
012345
0 5 100
0 2 10
0 4 30
1 2 5
2 3 50
3 5 10
4 3 20
4 5 60
0 5

输出样例:
输出源点到终点的最短路径。
0->4->3->5

答案:

void ShortestPath_DIJ(AMGraph G, int v0) {
    int n = G.vexnum;  // 顶点数量
    int v, i, j, min;

    // 初始化数组
    for (v = 0; v < n; v++) {
        S[v] = false;              // 初始均未确定最短路径
        D[v] = G.arcs[v0][v];      // 初始化为v0到v的直接距离
        if (D[v] < MaxInt)          // 若存在直接边
            Path[v] = v0;           // 前驱设为v0
        else
            Path[v] = -1;           // 不可达
    }

    // 处理源点
    S[v0] = true;  // v0加入已确定集合
    D[v0] = 0;     // v0到自身距离为0

    // 主循环(每次确定一个顶点的最短路径)
    for (i = 1; i < n; i++) {
        min = MaxInt;
        // 寻找当前未确定顶点中的最短路径顶点v
        for (j = 0; j < n; j++) {
            if (!S[j] && D[j] < min) {
                v = j;
                min = D[j];
            }
        }
        S[v] = true;  // 将顶点v加入已确定集合

        // 通过v更新邻接顶点的最短路径
        for (j = 0; j < n; j++) {
            //如果顶点j未确定,且通过v到j的路径更短
            if (!S[j] && (D[v] + G.arcs[v][j] < D[j])) {
                D[j] = D[v] + G.arcs[v][j];  // 更新最短距离
                Path[j] = v;                  // 更新前驱顶点
            }
        }
    }
}

接下来解释一下代码:

初始化后状态
S数组(是否已确定):[true, false, false, false, false, false]
(源点0已确定)

D数组(当前最短距离):[0, 32767, 10, 32767, 30, 100]

0→1:无直接路径 (32767)

0→2:直接路径10

0→3:无直接路径 (32767)

0→4:直接路径30

0→5:直接路径100

Path数组(前驱节点):[-1, -1, 0, -1, 0, 0]

第一次主循环 (i=1)
寻找最小距离顶点:

未确定顶点:1,2,3,4,5

最小距离:顶点2 (D[2]=10)

设置 v=2, min=10

标记顶点2已确定:

S[2] = true

更新邻居顶点(只考虑从顶点2出发的边:2→3):

顶点3:D[2] + G.arcs[2][3] = 10 + 50 = 60 < 32767
→ 更新 D[3]=60, Path[3]=2

其他顶点无更新(顶点2没有指向1,4,5的边)

更新后状态:

S:[true, false, true, false, false, false]

D:[0, 32767, 10, 60, 30, 100]

Path:[-1, -1, 0, 2, 0, 0]

第二次主循环 (i=2)
寻找最小距离顶点:

未确定顶点:1,3,4,5

最小距离:顶点4 (D[4]=30)

设置 v=4, min=30

标记顶点4已确定:

S[4] = true

更新邻居顶点(从顶点4出发的边:4→3, 4→5):

顶点3:D[4] + G.arcs[4][3] = 30 + 20 = 50 < 60
→ 更新 D[3]=50, Path[3]=4

顶点5:30 + 60 = 90 < 100
→ 更新 D[5]=90, Path[5]=4

更新后状态:

S:[true, false, true, false, true, false]

D:[0, 32767, 10, 50, 30, 90]

Path:[-1, -1, 0, 4, 0, 4]

第三次主循环 (i=3)
寻找最小距离顶点:

未确定顶点:1,3,5

最小距离:顶点3 (D[3]=50)

设置 v=3, min=50

标记顶点3已确定:

S[3] = true

更新邻居顶点(从顶点3出发的边:3→5):

顶点5:D[3] + G.arcs[3][5] = 50 + 10 = 60 < 90
→ 更新 D[5]=60, Path[5]=3

更新后状态:

S:[true, false, true, true, true, false]

D:[0, 32767, 10, 50, 30, 60]

Path:[-1, -1, 0, 4, 0, 3]

第四次主循环 (i=4)
寻找最小距离顶点:

未确定顶点:1,5

最小距离:顶点5 (D[5]=60)

设置 v=5, min=60

标记顶点5已确定:

S[5] = true

更新邻居顶点:

顶点5没有出边(或邻居已确定),无更新

第五次主循环 (i=5)
寻找最小距离顶点:

唯一未确定顶点1 (D[1]=32767)

设置 v=1, min=32767

标记顶点1已确定:

S[1] = true

更新邻居顶点:

顶点1有出边1→2,但顶点2已确定,无更新

最终结果
最短距离:D[5]=60

路径回溯:

Path[5]=3

Path[3]=4

Path[4]=0

Path[0]=-1

完整路径:0→4→3→5

posted @ 2025-06-24 16:00  雨花阁  阅读(12)  评论(0)    收藏  举报