最短路之dijkstra

最近真是......zoj很久没切题了,nbut上的几题又超时,阴影啊。。。。>_<

打算按照大牛的训练计划,改动下。先是最短路,参考了算法导论&&一本图论算法。


本质贪心,要求所有边的权值非负。

方法:设置一顶点集合:S,反复选择具有最短路径的顶点u属于V(点数)-s(起点)

并将u加入到S中。对u的所有出边进行松弛操作。

算法导论上对于dijkstra的算法:

dijkstra(G,w,s)
init(G,s)
S<--NULL//顶点集合S
Q<---V[G]//初始化Q,使其包含V中所有顶点。
while(Q!=NULL)
  do u <-- EXTRACT-MIN(Q)
    S <-- SU{u}
    for eachvertex v include to Adj[u]
        do relax(u,v,w)


Q为优先队列,以d(即每个点的最短路值)为优先值。体现其贪心。每次都找权值最小的点出队,然后经过该点松弛其他边。

为什么不允许负权边存在??

如图:



权值为7的点在加入集合S后变为6Dijkstra出错。

关于松弛技术:

实际上就是紧缩上界,松弛一条边的(u,v)的过程中,测试是否可以通过u对迄今找到的v的最短路进行改进。

目的||作用:可以减少最短路径估计得值d[v],并重新更新前驱域pre[v].

最短路之dijkstra_第1张图片


时间分析:

依赖于最小优先队列的具体实现。若采用数组实现则为O(V^2+E)

若是稀疏图的情况,利用二叉最小堆来实现时间复杂度为O((V+E)lgV)


实现代码:

#include <iostream>
#include <cstdio>
#define inf 10000000 //无穷大
#define MAXN 20     //顶点个数最大值
int n;
int Edge[MAXN][MAXN];//邻接矩阵
int S[MAXN];//集合S,实际上就是一个标记数组,0表示未加入集合,1表示加入集合
int min[MAXN];  //存取到每个点的最短路长度
int pre[MAXN];  //前驱结点,即父节点
using namespace std;
{
    int i,j;
    int u,v,w;
    cin>>n;//顶点个数n
    for(i=0;i<n;i++)
    { 
        for(j=0;j<n;j++)
        {
            if(i==j) Edge[i][j]=0
            else Edge[i][j]=inf;
        }
    }
    while(cin>>u>>v>>w)
    {
        if(u==-1&&v==-1&&w==-1) break;
        Edge[u][v]=w;
    }
    Dijsktra(0);//球顶点0到其他顶点的最短路径
    int num[MAXN]; //保存最短路上的各顶点的序号
    for(i=1;i<n;i++)
    {
        printf("%d\t",min[i]); 
        memset(num,0,sizeof(num));
        int k=0;//num数组的最后一个元素的下标。
        num[k]=i;
        while(pre[num[k]]!=0)
        {
            k++;
            num[k]=pre[num[k-1]];
        }
        k++;
        num[k]=0;
        for(j=k;j>0;j--)
            cout<<num[j]<<"-->";
        cout<<num[0]<<endl;
    }
    return 0;
}


运行结果:

最短路之dijkstra_第2张图片











你可能感兴趣的:(算法,测试,null,ini,include)