单源最短路径(Dijkstra)——贪心算法

Dijkstra算法是解单源最短路径问题的贪心算法。其基本思想是,设置顶点集合点集合S并不断地做贪心选择来扩充这个集合。一个顶点属于集合S当且仅当从源到该顶点的最短路径长度已知。初始时,S中仅含有源。设u是G的其一顶点。把从源到u且中间只经过S中顶点的路称为从源到u的特殊路径,并用数组Distance记录当前每个顶点所对应的最短特殊路径长度。Dijkstra算法每次从V-S中取出具有最短特殊路长度的顶占,Distance就记录了从源到所有其它顶点之间最短路径长度。

例如下图中的有向图,应用Dijkstra算法计算从源顶点1到其它顶点最短路径的过程列表在下表中。

算法过程描述:

表格中默认选取的起始顶点为1顶点,所以本问题就转化为求解1顶点到2, 3, 4, 5这几个顶点的最短路径。首先初始条件列出1顶点到2, 3, 4, 5各个顶点的距离,这个距离直接在图的存储邻接矩阵中得到,选取距离最近的一个也就是2顶点加入集合S,下面要进行的是比较关键的一步,这个时候应该去获取3, 4, 5三个顶点到集合S的最短距离(从1顶点出发,可以经过S中的任意顶点):将1到2顶点的距离加上2到各个点的距离,然后用这个距离来同1到各个顶点的距离相比较,谁小就取谁,以此类推,然后每次取Distance[]最小的值进入集合S。

这样下去,Distance[]中存放的就是每个顶点到集合S的最短距离,比如当前的集合只有1, 2,按照规则顶点4应该入选进集合S,因为Distance[3]没有入选集合的顶点中对应的Distance[]最小的顶点。现在需要计算3和5到新集合S={1, 2, 4}的最短距离,这个时候就只需要将Distance[2]和Distance[4]中的值(现在这里面的值表示集合S={1, 2}到顶点3和5顶点的最短距离),但是现在集合中加入了顶点4,怎么计算?计算方法如下:

Distance[3] + 邻接矩阵中顶点4到顶点3的距离 < Distance[2] ?

Distance[3]:(顶点4到S={1, 2}的最短距离)

Distance[2]: (顶点3到S={1, 2}的最短距离)

如果这个小于成立,那么很明显新的集合到顶点3的最小距离应该是先从S={1, 2}到顶点4的最短距离,然后再从顶点4到顶点3。

由于每一次的比较都是在上一次集合的最优结果中计算的,所以新计算出来的顶点3到集合S={1, 2, 4}的最短距离也是全局最优的。

对应的C语言代码如下:

#include <stdio.h>

#define M	65535 //无穷大
#define N	5 //顶点数

//Dijkstra算法函数,求给定顶点到其余各点的最短路径
//参数:邻接矩阵、出发点的下标、结果数组、路径前一点记录
void Dijkstra(int Cost[][N], int v0, int Distance[], int prev[])
{
    int s[N];
    int mindis,dis;
    int i, j, u;
    //初始化
    for(i=0; i<N; i++)
    {
        Distance[i] = Cost[v0][i];
        s[i] = 0;
        if(Distance[i] == M)
			prev[i] = -1;
        else
			prev[i] = v0;
    }
    Distance[v0] = 0;
    s[v0] = 1; //标记v0
    //在当前还未找到最短路径的顶点中,
    //寻找具有最短距离的顶点
    for(i=1; i < N; i++)
    {//每循环一次,求得一个最短路径
        mindis = M;
        u = v0;
        for (j=0; j < N; j++) //求离出发点最近的顶点
			if(s[j]==0 && Distance[j]<mindis)
			{
				mindis = Distance [j];
				u = j;
			} // if语句体结束,j循环结束
        s[u] = 1;
        for(j=0; j<N; j++) //修改递增路径序列(集合)
        if(s[j]==0 && Cost[u][j]<M)
        { //对还未求得最短路径的顶点
            //求出由最近的顶点 直达各顶点的距离
            dis = Distance[u] +Cost[u][j];
            // 如果新的路径更短,就替换掉原路径

            if(Distance[j] > dis)
            {
                Distance[j] = dis;
                prev[j] = u;
            }
        } // if 语句体结束,j循环结束
    } // i循环结束
}
// 输出最短路径
// 参数:路径前一点记录、出发点的下标、到达点下标
void PrintPrev(int prev[],int v0,int vn)
{
    int tmp = vn;
    int i, j;
    //临时存路径
    int tmpprv[N];
    //初始化数组
    for(i=0; i < N; i++)
		tmpprv[i] = 0;

    //记录到达点下标
    tmpprv[0] = vn+1;
    //中间点用循环记录
    for(i =0, j=1; j < N ;j++)
    {
        if(prev[tmp]!=-1 && tmp!=0)
        {
            tmpprv[i] = prev[tmp]+1;
            tmp = prev[tmp];
            i++;
        }
        else break;
    }

    //输出路径,数组逆向输出
    for(i=N-1; i >= 0; i--)
    {
        if(tmpprv[i] != 0)
        { //排除0元素
            printf("V%d", tmpprv[i]);
            if(i)  //不是最后一个输出符号
                printf("-->");
        }
    }
	printf("-->V%d", vn+1);
}
//主函数
int main()
{
    //给出有向网的顶点数组
    char *Vertex[N]={"V1", "V2", "V3", "V4", "V5"};
    //给出有向网的邻接矩阵
    int Cost[N][N]={
		{0, 10, M, 30, 100},
        {M, 0, 50, M, M},
        {M, M, 0, M, 10},
        {M, M, 20, 0, 60},
        {M, M, M, M, 0},
    };
    int Distance[N]; //存放求得的最短路径长度
    int prev[N];  //存放求得的最短路径
	int i;
    //调用Dijkstra算法函数,求顶点V1到其余各点的最短路径
    //参数:邻接矩阵、顶点数、出发点的下标、 结果数组
    Dijkstra(Cost, 0, Distance, prev);
    for(i=0; i < N; i++)
    {
        //输出最短路径长度
        printf("%s-->%s:%d\t", Vertex[0], Vertex[i], Distance[i]);
        //输出最短路径
        PrintPrev(prev, 0, i);
        printf("\n");
    }

    return 0;
}

程序运行结果截图:

参考文章:http://zengwu3915.blog.163.com/blog/static/278348972009109101834282/

单源最短路径(Dijkstra)——贪心算法

时间: 2024-10-18 16:41:36

单源最短路径(Dijkstra)——贪心算法的相关文章

单源最短路径_贪心算法

问题描述 给定带权有向图G =(V,E),其中每条边的权是非负实数.另外,还给定V中的一个顶点,称为源.现在要计算从源到所有其它各顶点的最短路长度.这里路的长度是指路上各边权之和. 策略与数据结构 其基本思想是,设置顶点集合S并不断地作贪心选择来扩充这个集合.一个顶点属于集合S当且仅当从源到该顶点的最短路径长度已知. 相关解释 观测域:假设起点为v点,观测域便为v点的四周,即v的所有邻接点: 点集 V:图中所有点的集合: 点集 S:已经找到最短路径的终点集合: 数组 D:存储观测域内能观测到的最

数据结构:单源最短路径--Dijkstra算法

Dijkstra算法 单源最短路径 给定一带权图,图中每条边的权值是非负的,代表着两顶点之间的距离.指定图中的一顶点为源点,找出源点到其它顶点的最短路径和其长度的问题,即是单源最短路径问题. Dijkstra算法 求解单源最短路径问题的常用方法是Dijkstra(迪杰斯特拉)算法.该算法使用的是贪心策略:每次都找出剩余顶点中与源点距离最近的一个顶点. 算法思想 带权图G=<V,E>,令S为已确定了最短路径顶点的集合,则可用V-S表示剩余未确定最短路径顶点的集合.假设V0是源点,则初始 S={V

单源最短路径Dijkstra算法

1.单源最短路径 函数:返回还未被收录顶点中dist最小者 1 Vertex FindMinDist(MGraph Graph, int dist[], int collected[]) 2 { 3 /*返回未被收录顶点中dist最小者*/ 4 Vertex MinV, V; 5 int MinDist = INFINITY; 6 7 8 for (V = 0; V < Graph->Nv; ++V) 9 { 10 if (collected[V] == false && di

(转)图算法单源最短路径Dijkstra算法(邻接表/邻接矩阵+优先队列STL)

一.前言 最短路径算法,顾名思义就是求解某点到某点的最短的距离.消耗.费用等等,有各种各样的描述,在地图上看,可以说是图上一个地点到达另外一个地点的最短的距离.比方说,我们把地图上的每一个城市想象成一个点,从一个城市到另一个城市的花费是不一样的.现在我们要从上海去往北京,需要考虑的是找到一条路线,使得从上海到北京的花费最小.有人可能首先会想到,飞机直达啊,这当然是时间消耗最小的方法,但是考虑到费用的高昂,这条线路甚至还不如上海到北京的高铁可取.更有甚者,假设国家开通了从上海到西藏,再从西藏到兰州

单源最短路径 dijkstra算法实现

本文记录一下dijkstra算法的实现,图用邻接矩阵表示,假设图为无向图,并且连通,有向图,不连通图的做法类似. 算法简述: 首先确定"单源"的源,假设是第0个顶点. 维护三个数组dist[], color[], path[],设其下标分别为0-i-n-1: dist[] 表示源点到顶点i的最短距离,在初始化时,如果源点到顶点i有路径,则初始化为路径的权重,否则初始化为INT_MAX: color[] 数组其实表示两个集合,即color[i]值为1的集合表示已经确定最短路径的点的集合,

单源最短路径Dijkstra、BellmanFord、SPFA【模板】

Dijkstra算法: 将所有点分为两个集合.如果源点s到u的最短路径已经确定,点u就属于集合Va,否则属于集合Vb. 1.将源点s到图中各点的直接距离当做初始值记录为s到各点的最短距离,不能到达的记为INF.S到S距离为0. 2.在集合Vb中的点中找一个点u,使得源点s到该点u路径长度最短,将u从Vb中除去,加到V1中.这时候求出了当前S到u的最短路径. 3.把新确定的点u更新s到集合Vb中每一个点v的距离,如果s到u的距离加上u到v的直接距离小于当前s到v的距离,则表示新找到的最短路径长度比

单源最短路径——Dijkstra算法学习

每次都以为自己理解了Dijkstra这个算法,但是过没多久又忘记了,这应该是第4.5次重温这个算法了. 这次是看的胡鹏的<地理信息系统>,看完之后突然意识到用数学公式表示算法流程是如此的好理解,堪称完美. 内容摘抄如下: 网络中的最短路径是一条简单路径,即是一条不与自身相交的路径,最短路径搜索的依据:若从S点到T点有一条最短路径,则该路径上的任何点到S的距离都是最短的. Dijkstra算法搜索步骤: 1.对起始点作标记S,且对所有顶点令D(X)=∞,Y=S: 2.对所有未做标记的点按以下公式

单源最短路径Dijkstra和优先级算法

百度百科:迪杰斯特拉算法. 代码实现如下: import java.util.Comparator; import java.util.PriorityQueue; import java.util.Scanner; class Node { int x; int value; } public class Main { static int N,M,cnt; static final int MAX = 105; static final int INF = 1000009; static N

Til the Cows Come Home(poj 2387 Dijkstra算法(单源最短路径))

Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 32824   Accepted: 11098 Description Bessie is out in the field and wants to get back to the barn to get as much sleep as possible before Farmer John wakes her for the morning milking. Bessi

单源最短路径、所有结点对的最短路径

算法核心:两个结点之间的一条最短路径包含着(包含于)其它的最短路径.[最短路径性质] 1.单源最短路径Dijkstra 思路:计算每个结点到源结点的距离,压入最小优先队列Q,对Q中的元素进行如下循环操作: 1.从队列Q中弹出最小元素u 2.将u并入S 3.对u的邻接表中每个结点v,调用Relax(u,v,w)更新结点v到源结点s的距离 直至Q为空. 伪代码: Initialize-Single-Source(G,s) for each vertex v in G.v v.d = MAX v.p