1. 程式人生 > >圖|最短路徑——迪傑斯特拉(Dijkstra)弗洛伊德(Floyd)

圖|最短路徑——迪傑斯特拉(Dijkstra)弗洛伊德(Floyd)

最短路徑——迪傑斯特拉(Dijkstra)弗洛伊德(Floyd)

一、迪傑斯特拉演算法(Dijkstra)

1. 問題:

求從每個源點到其餘各頂點的最短路徑。

2.儲存結構:

1)圖的儲存結構: 帶權的鄰接矩陣
2)輔助陣列:
一維陣列dist:dist[ i ]表示當前求出的從源點到頂點 i 的路徑長度,其初始狀態為鄰接矩陣第 i 行的值;
二維陣列path:二維陣列第 i 行path[ i ]表示源點到 i 的路徑中經過的頂點下標集合,其初始值為 -1 。
3)演算法實現:

void dijkstra(MGraph G, int v) {
    int
dist[MAXSIZE]; //dist[i]:源點到點 i 的路徑長度 int path[MAXSIZE][MAXSIZE]; //path[i][]:源點到點 i 經過的頂點j下標集合 int i, j, k, m, min, n, flag; for(i=0; i<G.vexNum; i++) { //path[][]初始化為-1 for(j=0; j<G.vexNum; j++) { path[i][j] = -1; } } for
(i=0; i<G.vexNum; i++) { dist[i]=G.arcs[v][i]; //dist[]初始狀態為arcs[][]第v行 if(dist[i]!=0 && dist[i]!=INFINITY) {//與源點 v 有關係的頂點第一個經過的點為 v path[i][0]=v; } } n=0; //列印最短路徑時對應第%d條 flag=1; //迴圈結束標誌 //從小到大找最短路徑 while(flag) { k=
0; //每一輪迴圈中要選擇的最短路徑長度對應的頂點下標 min=INFINITY; //每一輪迴圈中要選擇的最短路徑長度 for(j=0; j<G.vexNum; j++) { //找dist最小值 if(dist[j]!=0 && dist[j]<min) { k=j; min=dist[j]; } } printf("第%d條最短路徑長度為%d--(", ++n, min); //顯示最短路徑 for(j=0; j<G.vexNum; j++) { if(path[k][j]!=-1) { //列印從源點到最短路徑頂點經過的頂點 printf("%d,", path[k][j]); } } printf("%d)\n", k); for(j=0; j<G.vexNum; j++) { //更新dist和path if(j!=k && G.arcs[k][j]!=INFINITY) { if(dist[k]+G.arcs[k][j]<dist[j]) { //用更短的路徑長度替換原來的dist dist[j]=dist[k]+G.arcs[k][j]; for(m=0; m<G.vexNum; m++) { //將path[k]複製到path[j]中 path[j][m]=path[k][m]; } m=0; while(m<G.vexNum && path[j][m]!=-1) {//找path[j]中最後一個數據的下標,即第1個-1的下標 m++; } path[j][m]=k; //將下標j加到path[j]的尾部 }//if }//if }//for dist[k]=0; //標誌該頂點已輸出 flag=0; //判斷路徑是否求完,若flag=1繼續求,否則結束 for(j=0; j<G.vexNum; j++) { if(dist[j]!=0 && dist[j]<INFINITY) { flag = 1; } }//for }//while for(i=0; i<G.vexNum; i++) { if(dist[i]==INFINITY) { printf("由%d作為源點%d頂點無法到達\n", v, i); } } }

二、弗洛伊德演算法(Floyd)

1. 問題:

求每一對頂點間的最短路徑

2.儲存結構:

1)圖的儲存結構: 帶權的鄰接矩陣
2)輔助陣列:
二維陣列d:d[ i ][ j ]表示當前求出的從 i 到 j 的路徑長度;
二維陣列path:每個二維陣列元素path[ i ][ j ]是一個一維整形陣列,存放當前 i 到 j 的路徑做經過的頂點下標集合。
3)演算法實現:

void floyd(MGraph G) {
    int i, j, k, m, n, p;
    int d[MAXSIZE][MAXSIZE];
    PATHINT path[MAXSIZE][MAXSIZE];
    
    for (i=0; i<G.vexNum; i++) {        //初始化陣列 d 和 path
        for(j=0; j<G.vexNum; j++) {
            d[i][j] = G.arcs[i][j];
            for (k=0; k<MAXSIZE; k++) {
                path[i][j][k] = -1;
            }
        }
    }//for
    
    printf("\ndist的初值\n");
    for (i=0; i<G.vexNum; i++) {
        for (j=0; j<G.vexNum; j++) {
            printf("%6d", d[i][j]);
            printf("\t");
        }
        printf("\n");
    }
    
    for (i=0; i<G.vexNum; i++) {        //存放初始路徑
        for (j=0; j<G.vexNum; j++) {
            if (d[i][j]!=INFINITY && d[i][j]!=0) {
                path[i][j][0] = i;
                path[i][j][1] = j;
            }
        }//for-j
    }//for-i
    
    printf("\npath的初值\n");
    for (i=0; i<G.vexNum; i++) {
        for (j=0; j<G.vexNum; j++) {
            for (k=0; path[i][j][k]!=-1; k++) {
                printf("%d,", path[i][j][k]);
            }//for-k
            printf("\t");
        }//for-j
        putchar('\n');
    }//for-i
    
    for (k=0; k<G.vexNum; k++) {            //用經過點 k 的路徑更新上一次的路徑
        for (i=0; i<G.vexNum; i++) {
            if (i==k) {
                continue;
            }
            for (j=0; j<G.vexNum; j++) {
                if (j==k) {
                    continue;
                }
                if (d[i][k]+d[k][j] < d[i][j]) {// d(k)[i][j] = min{ d(-1)[i][j], d(-1)[i][k] + d(-1)[k][j]) }
                    d[i][j] = d[i][k] + d[k][j];
                    //m,n兩個for迴圈均為將經過k的更短的路徑複製的過程
                    for (m=0; m<G.vexNum && path[i][k][m]!=-1; m++) {
                        path[i][j][m] = path[i][k][m];
                    }//for-m
                    for (n=0; n<G.vexNum && path[k][j][n]!=-1; n++) {
                        if (n>1) {
                            m++;
                        }
                        path[i][j][m] = path[k][j][n];
                    }//for-n
                }//if
            }//for-j
        }//for-i
        printf("\ndist的第%d次迭代結果\n", k+1);
        for(m=0; m<G.vexNum; m++) {
            for (n=0; n<G.vexNum; n++) {
                printf("%6d", d[m][n]);
            }//for-n
            putchar('\n');
        }//for-m
        
        printf("\npath的第%d次迭代結果\n", k+1);
        for (i=0; i<G.vexNum; i++) {
            for (j=0; j<G.vexNum; j++) {
                for (p=0;path[i][j][p]!=-1; p++) {
                    printf("%d,", path[i][j][p]);
                }//for-p
                printf("\t");
            }//for-j
            putchar('\n');
        }//for-i
    }//for-k
}//floyd