Dijkstra标准模板

Dijkstra求最短路问题:单元求最短路,从任意点出发求得该点到达其他任意点的距离

Dijkstra其实是一种贪心策略,与出发点(即源点)所连接的点中找到距离最短的点(这个距离是源点到这个点的最短距离)再以这个点继续以这样的操作来找到最短距离的点(松弛操作)

Q:为什么离源点最近的那个节点与源点的连边是源点到那个节点的最短距离?

如下图:

A:根据图片我们可以得知如果这条边是源点到达该点的最短距离那一定是源点到达该点的最短距离,不管怎么用其他边去更新它都不如该边短.

Q:Dijkstra的贪心流程:

这里我们假设源点为点1.  节点间的距离为X(数字)。

由分步图我们可以得知与源点1相连的有点2和点3    这里我们就会有两个操作   1.确立源点的最短点;   2.松弛另一个或几个点.

由X(2),X(3)可以到达源点1 因为X(1—2)=1<X(1—3)=12,所以我门可以确定源点1到点2的最短距离为“1”  且  松弛点3即 dis[3]=12

这步我们可以获得 dis[2]=1(确定) dis[3]=12(未确定)。

下一步我们移步到点2(因为点2到源点的最短距离确定了因此由点2一定能更新出另一个最短点)由图得与点2相连的点有点3和点4,  因为X(2—3)=9>X(2—4)=3

所以同样的操作我们可以 确定点2到点4的距离为3,因为先前X(1—2)=1,X(2—4)=3所以X(1—4)=4(确定); 通过比较我们发现还可以松弛点3 X(1—3)=12>[X(1—2)=1+X(2—3)=9]即X(1—3)=10(未确定)

这步我们可以获得 dis[4]=4(确定) dis[3]=10(未确定)

步骤接下来也如此直到将n个节点全部进行n次操作那源点到每个节点的距离就确定了

代码:
DIjkstra部分:

void dijkstra()
{
    for(int k=1;k<=n;k++)
    {
        int minn=INF,pos;//贪心确定松弛点,并确定松弛点的坐标
        for(int i=1;i<=n;i++)
        {
            if(!vis[i]&&dis[i]<minn)
                minn=dis[i],pos=i;//pos为松弛点的坐标,minn为源点到松弛点的值
        }
        vis[pos]=true; 
        for(int i=1;i<=n;i++)
        {
            if(!vis[i]&&dis[i]>dis[pos]+edges[pos][i])//更新dis值
            dis[i]=dis[pos]+edges[pos][i];
        }
    }
    return;
}

代码解释

先由源点松弛节点再在被松弛的节点中找到最小的距源点最短点作为下一个松弛点且确定此点到源点的距离最短下次不需要再被松弛因此将此点vis[pos]=true;不必再对此点进行操作

第一部分:

for(int k=1;k<=n;k++)
{
    int minn=INF,pos;
    for(int i=1;i<=n;i++)
    {
        if(!vis[i]&&dis[i]<minn)
             minn=dis[i],pos=i;
    }
}
//pos为此松弛点的坐标 minn为此松弛点的值
//此部分代码目的为找到下一个松弛点并确定松弛点到源点的值
//dis[松弛点]确定不再改变因此我们需要将vis[pos]=true
//dis[松弛点]==minn确定并为下一步松弛记录坐标pos

第二部分:

for(int i=1;i<=n;i++)
{
    if(!vis[i]&&dis[i]>dis[pos]+edges[pos][i])
    dis[i]=dis[pos]+edges[pos][i];
}
//由于上一步将松弛点vis[pos]=true因此在此操作中if(!vis[i])即排除松弛点
//并枚举1~n中可以被松弛的点,并对其进行松弛即dis[i]=dis[pos]+edges[pos][i]

关于dis[ i ]=dis[pos]+edges[pos][ i ]的解释

dis[pos]为松弛点在第一部分我们可以确定它的值,edges[pos][i]在输入时可以确定其值

所以当dis[i]>dis[pos]+edges[pos][i]时我们便可以松弛这个点的值即可以求得dis[源点—i]的值

整体代码:

#include <iostream>
#include <cstdio>
#include <iomanip>
#include <cstring>
using namespace std;
typedef int insert;
#define in cin
#define out cout
const int INF=0x3f3f3f3f;
const int N=500+50;
insert n,m,x,y,z,dis[N],vis[N],edges[N][N];
insert startpoint;

void value()
{
    memset(edges,INF,sizeof(edges));
    memset(dis,INF,sizeof(dis));
    for(int i=1;i<=m;i++)
    {
        in>>x>>y>>z;
        edges[x][y]=z;
    }
    dis[startpoint]=0;
    return;
}

void dijkstra()
{
    for(int k=1;k<=n;k++)
    {
        insert minn=INF,pos;
        for(int i=1;i<=n;i++)
        {
            if(!vis[i]&&dis[i]<minn)
                minn=dis[i],pos=i;
        }
        vis[pos]=true;
        for(int i=1;i<=n;i++)
        {
            if(!vis[i]&&dis[i]>dis[pos]+edges[pos][i])
            dis[i]=dis[pos]+edges[pos][i];
        }
    }
    return;
}
int main()
{
    in>>n>>m>>startpoint;
    value();
    dijkstra();
    for(int i=1;i<=n;i++)
        out<<startpoint<<"-->"<<i<<" "<<dis[i]<<endl; 
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/CCCPKeay/p/10287732.html
今日推荐