单源最短路径_贪心算法

问题描述

给定带权有向图G =(V,E),其中每条边的权是非负实数。另外,还给定V中的一个顶点,称为源。现在要计算从源到所有其它各顶点的最短路长度。这里路的长度是指路上各边权之和。

策略与数据结构

基本思想是,设置顶点集合S并不断地作贪心选择来扩充这个集合。一个顶点属于集合S当且仅当从源到该顶点的最短路径长度已知。

相关解释

  • 观测域:假设起点为v点,观测域便为v点的四周,即v的所有邻接点;
  • 点集 V:图中所有点的集合;
  • 点集 S:已经找到最短路径的终点集合;
  • 数组 D:存储观测域内能观测到的最短路径,算上起点一共 n 个数值。比如 D[k] 对应在观测域中能观测到的,到顶点 k 的最短路径;
  • 邻接矩阵 a:存储着有权图中的边的信息,是一个二维数组。比如 a[1][2] = 5 表示在有权图中,点 1 和点 2 之间有边,且边的权值为 5。如果两点之间没边,则用负数或则无穷大(∞)表示。
  • 单源最短路径算法,又称迪杰斯特拉算法

    Dijkstra算法特点:以起始点为中心向外层层扩展,直到扩展到终点为止,是一种广度优先搜索方法。

    Dijkstra算法原理:最优子路径存在(贪心算法的最优子结构性质)。假设S→F存在一条最短路径SF,且该路径经过点A,那么SA子路径一定是S→A的最短路径。

算法步骤

  • 第一步:初始化点集 S,将起点 v 收入 S 中。初始化数组 D:D[k] = a[v][k];
  • 第二步:找寻次短路径。即查找数组 D,找出观测域中最短路径(v, j):D[j] = min(D[k] | k 不属于 S)。将点 j 加入点集 S 中;
  • 第三步:将 j 的邻接点并入观测域,即用 j 的邻接点更新数组 D;
  • 第四步:不断重复第二步和第三步,直到节点全部压入 S 中为止。

注:贪心算法的思想主要就体现在第二步和第三步之中。

复杂性

最大嵌套用到双层for循环,最内层代码块可看做O(1),所以该算法的时间复杂度是O(n^2)

代码

package 贪心算法;

import java.util.Scanner;

public class 单源最短路径 {
    public static void main(String[] args)
    {
        Scanner input = new Scanner(System.in);

        System.out.print("请输入图的顶点和边的个数(格式:顶点个数 边个数):");
        int n = input.nextInt(); //顶点的个数
        int m = input.nextInt(); //边的个数

        System.out.println();

        int[][] a = new int[n + 1][n + 1];
        //初始化邻接矩阵
        for(int i = 0; i < a.length; i++)
        {
            for(int j = 0; j < a.length; j++)
            {
                a[i][j] = -1; //初始化没有边
            }
        }

        System.out.println("请输入图的路径长度(格式:起点 终点 长度):");
        //总共m条边
        for(int i = 0; i < m; i++)
        {
            //起点,范围1到n
            int s = input.nextInt();
            //终点,范围1到n
            int e = input.nextInt();
            //长度
            int l = input.nextInt();

            if(s >= 1 && s <= n && e >= 1 && e <= n)
            {
                //无向有权图
                a[s][e] = l;
                a[e][s] = l;
            }
        }

        System.out.println();

        //距离数组
        int[] dist = new int[n+1];
        //前驱节点数组
        int[] prev = new int[n+1];

        int v =1 ;//顶点,从1开始
        dijkstra(v, a, dist, prev);
    }

    /**
     * 单源最短路径算法(迪杰斯特拉算法)
     * @param v 顶点
     * @param a 邻接矩阵表示图
     * @param dist 从顶点v到每个点的距离
     * @param prev 前驱节点数组
     */
    public static void dijkstra(int v, int[][] a, int[] dist, int[] prev)
    {
        int n = dist.length;
        /**
         * 顶点从1开始,到n结束,一共n个结点
         */
        if(v > 0 && v <= n)
        {
            //顶点是否放入的标志
            boolean[] s = new boolean[n];

            //初始化
            for(int i = 1; i < n; i++)
            {
                //初始化为 v 到 i 的距离
                dist[i] = a[v][i];
                //初始化顶点未放入
                s[i] = false;
                //v到i无路,i的前驱节点置空
                if(dist[i] == -1)
                {
                    prev[i] = 0;
                }
                else
                {
                    prev[i] = v;
                }
            }

            //v到v的距离是0
            dist[v] = 0;
            //顶点放入
            s[v] = true;

            //共扫描n-2次,v到v自己不用扫
            for(int i = 1; i < n - 1; i++)
            {
                int temp = Integer.MAX_VALUE;
                //u为下一个被放入的节点
                int u = v;

                //这个for循环为第二步,观测域为v的观测域
                //遍历所有顶点找到下一个距离最短的点
                for(int j = 1; j < n; j++)
                {
                    //j未放入,且v到j有路,且v到当前节点路径更小
                    if(!s[j] && dist[j] != -1 && dist[j] < temp)
                    {
                        u = j;
                        //temp始终为最小的路径长度
                        temp = dist[j];
                    }
                }

                //将得到的下一节点放入
                s[u] = true;

                //这个for循环为第三步,用u更新观测域
                for(int k = 1; k < n; k++)
                {
                    if(!s[k] && a[u][k] != -1)
                    {
                        int newdist=dist[u] + a[u][k];
                        if(newdist < dist[k] || dist[k] == -1)
                        {
                            dist[k] = newdist;
                            prev[k] = u;
                        }
                    }
                }
            }
        }

        for(int i = 2; i < n; i++)
        {
            System.out.println(i + "节点的最短距离是:"
                + dist[i] + ";前驱点是:" + prev[i]);
        }

    }
}
/**
运行结果
请输入图的顶点和边的个数(格式:顶点个数 边个数):5 7

请输入图的路径长度(格式:起点 终点 长度):
1 2 4
1 4 2
2 3 4
2 4 1
3 4 1
3 5 3
4 5 7

2节点的最短距离是:3;前驱点是:4
3节点的最短距离是:3;前驱点是:4
4节点的最短距离是:2;前驱点是:1
5节点的最短距离是:6;前驱点是:3
**/

 

原文地址:https://www.cnblogs.com/LieYanAnYing/p/12040288.html

时间: 2024-08-01 06:58:54

单源最短路径_贪心算法的相关文章

图的单源最短路径:Dijkstra算法实现

本文介绍的是图的非负权值的单源最短路径问题.问题的提出是,对于有权图D,t提供源点v,要找到从v到其他所有点的最短路径,即单源最短路径问题,在本文中,解决这一问题,是普遍比较熟悉的Dijkstra算法. 算法核心思想参见维基.简而言之,设集合S存放已经求出了最短路径的点.初始状态S中只有一个点v0,之后每求得v0到vn的最短路径,就会更新v0到所有vn邻接的点的一致的最短路径(不一定是最终的最短路径),如此重复,每次会确定v0到一个点的最短路径,确定好的点加入S中,直至所有点进入S结束.在本文中

单源最短路径(dijkstra算法)php实现

做一个医学项目,其中在病例评分时会用到单源最短路径的算法.单源最短路径的dijkstra算法的思路如下: 如果存在一条从i到j的最短路径(Vi.....Vk,Vj),Vk是Vj前面的一顶点.那么(Vi...Vk)也必定是从i到k的最短路径.Dijkstra是以最短路径长度递增,逐次生成最短路径的算法.例如:对于源顶点V0,首先选择其直接相邻的顶点中长度最短的顶点Vi,那么当前已知可得从V0到达Vj顶点的最短距离dist[j]=min{dist[j],dist[i]+cost[i][j]}.假设G

单源最短路径问题-Dijkstra算法

同样是层序遍历,在每次迭代中挑出最小的设置为已知,收敛 表初始化 void InitTable(Vertex Start, Graph G, Table T) { int i; ReadGraph(G, T); for (i=0; i<NumVertex; i++) { T[i].Known = False; T[i].Dist = Infinity; T[i].Path = NotAVertex; } T[Start].dist = 0; } 显示实际路径 void PrintPath(Ver

数据结构与算法--单源最短路径算法之dijkstra

单源最短路径之dijkstra算法 最优子问题:dis(s,...,e)是s到e的最短路径,在这条路径上的所有点之间dis(pi,pj)距离是最小的. 算法思路: 首先初始化,dis[s][i]是s到i的距离,直接相连的就是其距离,不直接相连的就是无穷大 下面是算法主要模块: 1.选取dis[i]最小的点加入到P{S}中, 2.计算是否更新dis[j],j是和i直接相连的 3.重复以上步骤,直到e

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

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

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

[C++]单源最短路径:迪杰斯特拉(Dijkstra)算法(贪心算法)

1 Dijkstra算法 1.1 算法基本信息 解决问题/提出背景 单源最短路径(在带权有向图中,求从某顶点到其余各顶点的最短路径) 算法思想 贪心算法 按路径长度递增的次序,依次产生最短路径的算法 [适用范围]Dijkstra算法仅适用于[权重为正]的图模型中 时间复杂度 O(n^3) 补充说明 亦可应用于[多源最短路径](推荐:Floyd算法(动态规划,O(n^3))) Dijkstra 时间复杂度:O(n^3) 1.2 算法描述 1.2.1 求解过程(具体思路) 1.2.2 示例 1.2

Dijkstra算法求单源最短路径

1.最短路径 在一个连通图中,从一个顶点到另一个顶点间可能存在多条路径,而每条路径的边数并不一定相同.如果是一个带权图,那么路径长度为路径上各边的权值的总和.两个顶点间路径长度最短的那条路径称为两个顶点间的最短路径,其路径长度称为最短路径长度. 最短路径在实际中有重要的应用价值.如用顶点表示城市,边表示两城市之间的道路,边上的权值表示两城市之间的距离.那么城市A到城市B连通的情况下,哪条路径距离最短呢,这样的问题可以归结为最短路径问题. 求最短路径常见的算法有Dijkstra算法和Floyd算法

数据结构之单源最短路径(迪杰斯特拉算法)-(九)

最开始接触最短路径是在数据结构中图的那个章节中.运用到实际中就是我在大三参加的一次美赛中,解决中国的水资源问题.所谓单源最短路径,就是一个起点到图中其他节点的最短路径,这是一个贪心算法. 迪杰斯特拉算法原理(百科): 按路径长度递增次序产生算法: 把顶点集合V分成两组: (1)S:已求出的顶点的集合(初始时只含有源点V0) (2)V-S=T:尚未确定的顶点集合 将T中顶点按递增的次序加入到S中,保证: (1)从源点V0到S中其他各顶点的长度都不大于从V0到T中任何顶点的最短路径长度 (2)每个顶