重新教自己学算法之图的最短路(十二)

最短路在实际中有很多应用。最短路的路劲一般不再是路径上的数目,而是路径边上的权值之和。所以最短路径都是用在带权有向图上面的。在最短路径方面,有两个著名的算法:Dijkstra算法和Floyd算法。

1:1.Dijkstra算法-从某个点到其余各点的最短路径(贪心算法)
下面根据例子实际说明一下:
这里写图片描述这里写图片描述

这里写图片描述

  1. 一开始我们初始化已选择点集S,我们假设源点为v0,所以先把v0加入S,此时S = {v0}。
  2. 我们首先遍历除v0之外的所有点,发现v0无法直接到达v1和v3,所以距离为∞。而其他三个点中,到v2点的距离最近,此时我们选择v2加入S,此时S = {v0,v2}。
  3. 接下来再一次遍历除S内元素之外的所有点。我们可以知道,如果想知道v0到vk的最短距离,则最短距离有两种情况:
    (1):v0到vk上的权值。
    (2):或者是之间经历了其他顶点,假设经历了一个顶点vj,则最短距离 = v0到vj的最短路径 + vj到vk上的权值。而这个vj就是我们加入到集合S里面的顶点。
    所以我们开始更新第一次的路径长度结果,发现通过新加入的点(即v2),我们可以到达v3,此时路径长度 = v0到v2的权值 + v2到v3权值 = 60。而其他点的路径长度没有被更新或者经历了v2后的路径长度并不比更新前的小。最后我们找到路径长度最短的点v4,加入S,此时S = {v0,v2,v4}。

4.再次按照3中的形式进行遍历S之外的点。 此时我们看到加入了v4后,我们到达v3的路径长度被缩短到了50,这个50 = v0到v4的权值 + v4到v3权值,而v0到v4的权值已经被记录过,所以可以直接使用,所以这个距离很容易就被求出。接下来v5的长度更新和v3一样,就不在详述了,最后找到路径长度最短的点v3,加入S,此时S = {v0,v2,v4,v3}。
5. 再次按照3中的形式进行遍历S之外的点。更新了v5的路径长,找到路径长度最短的点v5,加入S,此时S ={v0,v2,v4,v3,v5}。而此时我们发现,只剩下v1,但是从源点v0到v1的距离依然是∞,说明v0没有和v1连通。此时我们将v1加入S,这时集合S的长度 = 顶点数 = 6,算法结束。

源代码如下:

//scdn博客地址 :http://blog.csdn.net/u010006643/article/details/45693401

#include <iostream>
#include <cstring>
#include <queue>
using namespace std;

#define MAX 100
#define INT_MAX 10000
#define max(x,y)(x>y?x:y)

typedef struct 
{
    int matrix[100][100];
    int num;
}Graph;

int initNode = 0;
int* shortPath = NULL;
int* S = NULL;
Graph example;


int initGraph()
{
    int i,j;
    for(i = 0; i < MAX; i++){
        for (j = 0; j < MAX; j++)
        {
            example.matrix[i][j] = INT_MAX;
        }
    }
    example.num = 0;
}

void createPoint()
{
    int i, j, val;
    initGraph();
    while(cin>>i>>j>>val)
    {
        if(0 == i && 0 == j)
            break;
        example.matrix[i][j] = val;
        example.num = max(example.num,i);
        example.num = max(example.num,j);
    }
}

void printResult()
{
    cout<<"---------------"<<endl;
    for (int i = 0; i <= example.num; ++i)
    {

        if(i != initNode)
            cout<<initNode<<"->"<<i<<":"<<shortPath[i]<<" "<<endl;

    }
}

void dijkstra()
{
    int i, j;
    shortPath = new int[example.num + 1];
    S = new int[example.num + 1];
    int count = 0;
    int nowProp;
    int minPoint,minval;
    for(i = 0; i <= example.num; i++)
    {
        S[i] = -1;
        shortPath[i] = INT_MAX;
    }
    S[initNode] = 1;
    count++;
    nowProp = initNode;

    while(count <= example.num + 1)
    {
        minPoint = -1, minval = INT_MAX + 1;
        for(i = 0; i <= example.num; i++)
        {
            if(S[i] != 1)
            {
                if(example.matrix[initNode][i] < shortPath[i])
                {
                    shortPath[i] = example.matrix[nowProp][i];
                }
                if(example.matrix[nowProp][i] + shortPath[nowProp] < shortPath[i])
                {
                    shortPath[i] = example.matrix[nowProp][i] + shortPath[nowProp];
                }
                if(shortPath[i] < minval)
                {
                    minval = shortPath[i];
                    minPoint = i;
                }
            }
        }
        S[minPoint] = 1;
        nowProp = minPoint;
        count++;
    }
}

int main(int argc, char const *argv[])
{
    initNode =0;
    createPoint();
    dijkstra();
    printResult();
    return 0;
}
//0 2 10 0 4 30 0 5 100 1 2 5 2 3 50 3 5 10 4 5 60 4 3 20 0 0 0

2.Floyd算法-每对点之间的最短路径(动态规划)
Floyd算法主要的是动态规划的思想(下面的介绍来自于这篇博客)。
从任意节点i到任意节点j的最短路径不外乎2种可能,1是直接从i到j,2是从i经过若干个节点k到j。所以,我们假设Dis(i,j)为节点u到节点v的最短路径的距离,对于每一个节点k,我们检查Dis(i,k) + Dis(k,j) < Dis(i,j)是否成立,如果成立,证明从i到k再到j的路径比i直接到j的路径短,我们便设置Dis(i,j) = Dis(i,k) + Dis(k,j),这样一来,当我们遍历完所有节点k,Dis(i,j)中记录的便是i到j的最短路径的距离。

算法描述:
1. 从任意一条单边路径开始。所有两点之间的距离是边的权,如果两点之间没有边相连,则权为无穷大。   
2. 对于每一对顶点 u 和 v,看看是否存在一个顶点 w 使得从 u 到 w 再到 v 比己知的路径更短。如果是更新它。

我觉得上面的介绍已经基本上差不多了,下面是一个带权有向图和它的邻接矩阵。
这里写图片描述

(1)D(−1): 邻接矩阵的初始状态。
(2)D(0): 此时我们对于节点0,检查Dis(i,0) + Dis(0,j) < Dis(i,j)是否成立。 循环后我们发现Dis(2,0) + Dis(0,1) = 7 < Dis(2,1) = ∞,所以替换掉 Dis(2,1)=7。
(3)D(1) : 按照2里面的方法,我们发现Dis(0,1) + Dis(1,2) = 6 < Dis(0,2) = 11。替换掉Dis(0,2) 。重复该步骤,直到循环结束。

而根据图我们可以知道这个主程序是三层循环,所以时间复杂度为O(n3)。但是Dijkstra算法只是从一个源点到其他各点的最短路径,而如果找寻所有点的话,还是需要一个外循环的,所以其实从这个角度看,Dijkstra和Floyd的时间复杂度可以说是一样的,只不过Floyd的思想稍微简单一些。
这里写图片描述

代码如下:

//scdn博客地址 :http://blog.csdn.net/u010006643/article/details/45693401

#include <iostream>
#include <cstring>
#include <queue>
using namespace std;

#define MAX 100
#define INT_MAX 10000
#define max(x,y)(x>y?x:y)
typedef struct{
    int matrix[MAX][MAX]; //邻接矩阵
    int num;// 最大的顶点数
}Graph;

Graph example;

void initGraph()
{
    int i, j;
    for(i = 0; i < MAX; i++)
    {
        for(j = 0; j < MAX; j++)
        {
            example.matrix[i][j] = INT_MAX;
            example.matrix[j][j] = 0;
        }
    }
    example.num = 0;
}

void createPoint()
{
    int i , j, val;
    initGraph();
    while(cin>>i>>j>>val)
    {
        if(0 == i && 0 == j)break;
        example.matrix[i][j] = val;
        example.num = max(example.num, i);
        example.num = max(example.num, j);
    }
}

void printResult()
{
    cout<<"----------------"<<endl;
    for (int i = 0; i <= example.num; ++i)
    {
        for (int j = 0; j <= example.num; ++j)
        {
            cout<<example.matrix[i][j]<<"  ";
        }
        cout<<endl;
    }
}

void Floyd()
{
    int i, j, k;
    for(k = 0; k <= example.num; k++)
    {
        for(i = 0; i <= example.num; i++)
        {
            for ( j = 0; j <= example.num; j++)
            {
                if(example.matrix[i][k] + example.matrix[k][j] < example.matrix[i][j])
                {
                    example.matrix[i][j] = example.matrix[i][k] + example.matrix[k][j];
                }
            }
        }
    }
}

int main()
{
    createPoint();
    Floyd();
    printResult();
    return 0;
}

//0 1 4 0 2 11 1 0 6 1 2 2 2 0 3 0 0 0
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值