最短路徑問題-Floyd算法


具體步驟和圖解看這個:https://www.cnblogs.com/ssyfj/p/9495960.html

一看這個就懂了-傻子也能看懂的弗洛伊德算法https://www.cnblogs.com/wangyuliang/p/9216365.html

知識點:

1)Floyd算法適用於APSP(All Pairs Shortest Paths,多源最短路徑),是一種動態規划算法,稠密圖效果最佳。

2)時間復雜度比較高O(n*3),不適合計算大量數據。

3)可以算出任意兩個節點之間的最短距離

4)無論是迪傑斯特拉算法還是弗洛伊德算法,對於有向圖,無向圖都是可以使用的。另外我們的最短路徑一般都是針對有環圖,無環圖使用拓撲排序可以獲得

5)弗洛伊德算法是用來求所有頂點到所有頂點的時間復雜度。

6)Floyd(
Floyd-Warshall)算法邊權可正可負,但是不能解決帶有“負權回路”(或者叫“負權環”)的圖,因為帶有“負權回路”的圖沒有最短路。
7)其實如果一個圖中帶有“負權回路”那么這個圖則沒有最短路。
(如果存在一個環(從某個點出發又回到自己的路徑),而且這個環上所有權值之和是負數,那這就是一個負權環,也叫負權回路)
如下圖:不存在1號頂點到3號頂點的最短路徑。因為1->2->3->1->2->3->...->1->2->3這樣路徑中,
每繞一次1->-2>3這樣的環,最短路就會減少1,永遠找不到最短路。

1:Floyd算法過程矩陣的計算----十字交叉法:

方法:兩條線,從左上角開始計算一直到右下角 如下所示

給出矩陣,其中矩陣A是鄰接矩陣,而矩陣Path記錄u,v兩點之間最短路徑所必須經過的點

 

相應計算方法如下:

最后A3即為所求結果

2:實現代碼

1)弗洛伊德算法定義了兩個二維矩陣:
矩陣D記錄頂點間的最小路徑 ;例如D[0][3]= 10,說明頂點0 到 3 的最短路徑為10。
矩陣P記錄頂點間最小路徑中的中轉點 ;例如P[0][3]= 1 說明,0 到 3的最短路徑軌跡為:0 -> 1 -> 3。
它通過3重循環,k為中轉點,v為起點,w為終點,循環比較D0[v][w] 和 D0[v][k] + D0[k][w] 最小值,如果D0[v][k] + D0[k][w] 為更小值,
則把D0[v][k] + D0[k][w] 覆蓋保存在D1[v][w]中。
2)核心思想:D1[v][w] = min{D0[v][k] + D0[k][w],D0[v][w]}【D0代表原來未更新前的數據,D1表示我們修改更新后的新的數據】
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include "queue.h"

#define MAXVEX 100    //最大頂點數
#define INFINITY 65535    //用0表示∞

typedef char VertexType;    //頂點類型,字符型A,B,C,D...
typedef int EdgeType;    //邊上權值類型10,15,...

//鄰接矩陣結構
typedef struct
{
    VertexType vers[MAXVEX];    //頂點表
    EdgeType arc[MAXVEX][MAXVEX];    //鄰接矩陣,可看作邊表
    int numVertexes, numEdges;    //圖中當前的頂點數和邊數
}MGraph;

typedef int Dist[MAXVEX][MAXVEX];    //存放各個頂點到其余頂點的最短路徑權值和
typedef int Path[MAXVEX][MAXVEX];    //存放各個頂點到其余頂點前驅頂點位置

//創建鄰接矩陣
void CreateMGraph(MGraph* G);
//顯示鄰接矩陣
void showGraph(MGraph G);

void Floyd(MGraph G,Path* path,Dist* dist);
void ShowDistAndPath(Path P, Dist D,int n);

void Floyd(MGraph G, Path* path, Dist* dist)
{
    int i,j,k;

    //初始化path和dist
    for (i = 0; i < G.numVertexes;i++)
    {
        for (j = 0; j < G.numVertexes;j++)
        {
            (*dist)[i][j] = G.arc[i][j];
            (*path)[i][j] = j;    //初始化為這個的一個好處就是自己到自己的路徑就是自己,我們不用修改
        }
    }

    //使用弗洛伊德核心算法,三層循環求解
    for (k = 0; k < G.numVertexes;k++)
    {
        for (i = 0; i < G.numVertexes;i++)
        {
            for (j = 0; j < G.numVertexes;j++)
            {
                if ((*dist)[i][j]>((*dist)[i][k]+(*dist)[k][j])&&i!=j)
                {
                    //將權值和更新,路徑也變為中轉點
                    (*dist)[i][j] = (*dist)[i][k] + (*dist)[k][j];
                    (*path)[i][j] = (*path)[i][k];
                }
            }
        }
    }
}

void ShowDistAndPath(Path P, Dist D,int n)
{
    int i, j;
    printf("Printf Dist:\n");
    for (i = 0; i < n;i++)
    {
        for (j = 0; j < n; j++)
        {
            if (i==j)
                printf("    0");    //需要將我們的無窮轉換一下再顯示
            else
                printf("%5d", D[i][j]);
        }
        printf("\n");
    }

    printf("Printf Path:\n");
    for (i = 0; i < n; i++)
    {
        for (j = 0; j < n; j++)
            printf("%5d", P[i][j]);
        printf("\n");
    }
}

int main()
{
    MGraph MG;
    CreateMGraph(&MG);
    showGraph(MG);
    Path path;
    Dist dist;
    Floyd(MG, &path, &dist);
    ShowDistAndPath(path, dist, MG.numVertexes);
    system("pause");
    return 0;
}

//生成鄰接矩陣
void CreateMGraph(MGraph* G)
{
    int i, j, k, w;
    G->numVertexes = 9;
    G->numEdges = 16;
    //讀入頂點信息
    G->vers[0] = 'A';
    G->vers[1] = 'B';
    G->vers[2] = 'C';
    G->vers[3] = 'D';
    G->vers[4] = 'E';
    G->vers[5] = 'F';
    G->vers[6] = 'G';
    G->vers[7] = 'H';
    G->vers[8] = 'I';

    //getchar();    //可以獲取回車符
    for (i = 0; i < G->numVertexes; i++)
        for (j = 0; j < G->numVertexes; j++)
            G->arc[i][j] = INFINITY;    //鄰接矩陣初始化

    //創建了有向鄰接矩陣
    G->arc[0][1] = 1;
    G->arc[0][2] = 5;
    G->arc[1][2] = 3;
    G->arc[1][3] = 7;
    G->arc[1][4] = 5;
    G->arc[2][4] = 1;
    G->arc[2][5] = 7;
    G->arc[3][4] = 2;
    G->arc[3][6] = 3;
    G->arc[4][5] = 3;
    G->arc[4][6] = 6;
    G->arc[4][7] = 9;
    G->arc[5][7] = 5;
    G->arc[6][7] = 2;
    G->arc[6][8] = 7;
    G->arc[7][8] = 4;

    for (i = 0; i < G->numVertexes;i++)
        for (k = i; k < G->numVertexes;k++)
            G->arc[k][i] = G->arc[i][k];
}


//顯示鄰接矩陣
void showGraph(MGraph G)
{
    for (int i = 0; i < G.numVertexes; i++)
    {
        for (int j = 0; j < G.numVertexes; j++)
        {
            if (G.arc[i][j] != INFINITY)
                printf("%5d", G.arc[i][j]);
            else
                printf("    0");
        }
        printf("\n");
    }
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM