最短路-弗洛伊德算法&狄克斯特拉算法

最短路

1.多源最短路

定义:现有n个地点,求任意两点间的最短距离

算法:弗洛伊德(floyd)算法

思想:让每一个点成为中转点,进行"松弛"操作;

所谓松弛操作就是要搞出 A+B 最短路-弗洛伊德算法&狄克斯特拉算法_第1张图片
咱们从软院到计算机学院要走6个单位,但是我们让文学院作为中转点的话,就有了2+3=5<6的效果,这就是进行了松弛操作。我们尝试以不同的点进行松弛操作,保留最近的那种。

那么我们要实现弗洛伊德算法的存储的话,一般都是用邻接矩阵实际上就是二维数组来实现的。

以上图为例子>我们把它转换成表格,两路不通的视为无穷大,输入样例是用 999 代替,表格如下:
最短路-弗洛伊德算法&狄克斯特拉算法_第2张图片

代码实现:

#include 
#include 

using namespace std;

int a[10][10];
int main()
{
    int n;
    cin >> n;
    for(int i = 1; i <= n; i++)
    {
        for(int j = 1; j <= n; j++)
        {
            cin >> a[i][j];
        }
    }


    for(int k = 1; k <= n; k++) //k是我们尝试的各个中转点
    {
        for(int i = 1; i <= n; i++)  //i为起点,j为终点;起点终点也都要遍历一遍
        {
            for(int j = 1; j <= n; j++)
                if(a[i][j] > a[i][k] + a[k][j])  //松弛操作,比较距离,更短就更新
                {
                    a[i][j] = a[i][k] + a[k][j];
                }
        }
    }

    for(int i = 1; i <= n; i++)
    {
        for(int j = 1; j <= n; j++)
        {
            cout << a[i][j] << ' ';
        }
        cout << endl;
    }

    return 0;
}

输入输出:
最短路-弗洛伊德算法&狄克斯特拉算法_第3张图片

例题

洛谷P2910:Clear And Present Danger S
代码:

#include 
using namespace std;

int a[105][105], n;
int m;
int b[10005];

int main()
{
//输入
    cin >> n >> m; //n个岛屿
    for(int i = 1; i <= m; i++)
        cin >> b[i];
    for(int i = 1; i <= n; i++)
    {
        for(int j = 1; j <= n; j++)
        {
            cin >> a[i][j];
        }
    }
    for(int k = 1; k <= n; k++)
        for(int i = 1; i <= n; i++)
            for(int j = 1; j <= n; j++)
                if(a[i][j] > a[i][k] + a[k][j])
                    a[i][j] = a[i][k] + a[k][j];
    int ans = 0;
    for(int i = 1; i <= m - 1; i++)
        ans += a[b[i]][b[i + 1]];

    cout << ans;
    return 0;
}

2.单源最短路

定义:某一个地点到任意一个地点的最短距离

算法:迪杰斯特拉(dijkstral)算法

例子:求软院到其他学院的最短距离

思想:把所有点分为两个阵营,一个为已求出最短距离阵营,另一个为未求出最短距离阵营。把每一个未求出最短距离阵营的点依次加入到求出最短距离阵营(每次找的是离求出最短距离阵营最近的点),并用这个点作为中转点,进行松弛操作。

和弗洛伊德算法不同,狄克斯特拉算法需要我们再创建一个一维数组来存储指定点到其他点的最短距离;如图:
在这里插入图片描述

根据上述思想,软院因为是自己到自己所以就不需要考虑了,接着找离最短距离阵营最近的点也就是文学院,把它加入最短距离阵营,让文学院成为中转点去松弛其他未加入最短距离阵营的点,发现到计算机学院结果为5<6,所以将6更新为5,而到公教楼则是>4的就不会松弛成功;接着找距离文学院最近的点即公教楼,让公交楼加入最短距离阵营,再以公教楼为中转点去松弛剩下的计算机学院,结果>5松弛失败;最后只剩计算机学院,我们将他加入最短距离阵营。
更新完成后的表格数据为:0 2 5 4

代码实现

int dis[505]; ///最短距离
int n, m;
int book[505]; ///0表示未加入最短距离阵营,1表示最短距离阵营
const int inf = 0x3f3f3f3f; ///无穷大
void dijkstra()
{
    book[1] = 1; ///自己到自己不用求
    for(int i = 1; i <= n - 1; i++)
    {
        int minn = inf;
        int u;
        //找距离最短距离阵营最近的点u
        for(int j = 1; j <= n; j++)
        {
            if(book[j] == 0 && dis[j] < minn)
            {
            minn = dis[j];
            u = j;
            }
        }
        book[u] = 1;
        for(int j = 1; j <= n; j++)
        {
            if(book[j] == 0 && dis[j] > dis[u] + a[u][j])
            {
                dis[j] = dis[u] + a[u][j];
            }
        }
    }
}

例题

ACwing849最短路

代码:

#include 
using namespace std;

int a[505][505];
int dis[505]; //最短距离
int n, m;
int book[505]; //0表示未加入最短距离阵营,1表示最短距离阵营
const int inf = 0x3f3f3f3f; //无穷大
void dijkstra()
{
    book[1] = 1; //自己到自己不用求
    for(int i = 1; i <= n - 1; i++)
    {
        int minn = inf;
        int u;
        //找距离红色阵营最近的点u
        for(int j = 1; j <= n; j++)
        {
            if(book[j] == 0 && dis[j] < minn)
            {
                minn = dis[j];
                u = j;
            }               
        }
        book[u] = 1;
        for(int j = 1; j <= n; j++)
        {
            if(book[j] == 0 && dis[j] > dis[u] + a[u][j])
            {
                dis[j] = dis[u] + a[u][j];
            }
        }
    }
}

int main()
{
cin >> n >> m; //n个点,m条边
//初始化
    for(int i = 1; i <= n; i++)
    {
        for(int j = 1; j <= n; j++)
        {
            if(i == j)
                a[i][j] = 0;
            else
                a[i][j] = inf;
        }
    }
//输入边
    for(int i = 1; i <= m; i++)
    {
        int x, y, z;
        cin >> x >> y >> z;
        if(z < a[x][y])
            a[x][y] = z;
    }
    for(int i = 1; i <= n; i++)
        dis[i] = a[1][i];
    dijkstra();
    if(dis[n] < inf)
        cout << dis[n];
    else
        cout << -1;
        
    return 0;
    
}

你可能感兴趣的:(算法,算法,dijkstra)