最短路径及其算法和ArcGIS放射状流向地图

Posted GeomaticsCenter

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了最短路径及其算法和ArcGIS放射状流向地图相关的知识,希望对你有一定的参考价值。

             1.最短路径及其算法


        从某顶点出发,沿图的边到达另一顶点所经过的路径中,各边上权值之和最小的一条路径叫做最短路径(Shortest Path Algorithm)。解决最短路的问题有,Dijkstra算法,Bellman-Ford算法,Floyd算法和SPFA算法等。

      最短路径问题是图论研究中的一个经典算法问题,旨在寻找图(由结点和路径组成的)中两结点之间的最短路径。算法具体的形式包括:

(1)确定起点的最短路径问题- 即已知起始结点,求最短路径的问题。适合使用Dijkstra算法。

(2)确定终点的最短路径问题- 与确定起点的问题相反,该问题是已知终结结点,求最短路径的问题。在无向图中该问题与确定起点的问题完全等同,在有向图中该问题等同于把所有路径方向反转的确定起点的问题。

(3)确定起点终点的最短路径问题- 即已知起点和终点,求两结点之间的最短路径。

(4)全局最短路径问题- 求图中所有的最短路径。适合使用Floyd-Warshall算法

我们这里重点讨论Dijkstra算法:

                                      图1

        Dijkstra最短路径算法是一种单源最短路径,针对的是非负权边。所谓单源最短路径就是指定一个出发顶点,计算从该源顶点出发到其他所有顶点的最短路径。下面图2便是找出从节点A到节点B的累积权值最小的路径的过程:

最短路径及其算法和ArcGIS放射状流向地图
最短路径及其算法和ArcGIS放射状流向地图
最短路径及其算法和ArcGIS放射状流向地图
最短路径及其算法和ArcGIS放射状流向地图

                                     图2

       该图算法描述的是这样的场景:图由节点和带有方向的边构成,每条边都有相应的权值,路径规划(最短路径)算法就是要找出从节点A到节点B的累积权值最小的路径。例如下图3,最短路径表示为图4:

最短路径及其算法和ArcGIS放射状流向地图

                                  图3

最短路径及其算法和ArcGIS放射状流向地图

            图4.各顶点之间最短路径的表示

最短路径及其算法和ArcGIS放射状流向地图

该算法用c#的语言表示为:

最短路径及其算法和ArcGIS放射状流向地图

using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConAppDijkstra
{
    class Program
    {

        private const int MaxSize = 6;
        private const int INF = 32767;    //INF表示∞
        private const int MAXV = 4;    //最大顶点个数
        //结构体的成员定义里不能直接赋值,也就是等号后的应该移除,在你后面实例化整个结构体以后,
        //再对Study_Data[n].input=new double[50] 其他成员类似。顺便说下其实用class简单得多。

        struct VertexType
        {
            public string VexNo;        //顶点编号
            public string VexName;        //顶点名称
            public string otherInfo;     //顶点其他信息     
        } ;                               //顶点类型
        struct MGraph                    //图的定义
        {
            public int[,] edges;       //邻接矩阵
            public int n, e;             //顶点数,弧数
            public VertexType[] vexs; //存放顶点信息
        } ;                               //图的邻接矩阵类型

        static void Ppath(int[] path, int i, int v)  //前向递归查找路径上的顶点
        {
            int k;
            k = path[i];
            if (k == v) return;    //找到了起点则返回
            Ppath(path, k, v);    //找顶点k的前一个顶点v

            Console.Write("{0},", k);    //输出路径上的终点
           // Ppath(path, k, j);    //找顶点k的前一个顶点j
        }

        static void Ppath(MGraph g,int[] path, int i, int v)  //前向递归查找路径上的顶点
        {
            int k;
            k = path[i];
            if (k == v) return;    //找到了起点则返回
            Ppath(path, k, v);    //找顶点k的前一个顶点v

            Console.Write("{0},", g.vexs[k].VexName);    //输出路径上的终点
            // Ppath(path, k, j);    //找顶点k的前一个顶点j
        }

        static void Dispath(int[] dist, int[] path, int[] s, int n, int v)
        {
            int i;
            for (i = 0; i < n; i++)
            {
                if (s[i] == 1)
                {
                    Console.Write(" 从{0}到{1}的最短路径长度为:{2}\t路径为:", v, i, dist[i]);
                    Console.Write("{0},", v);    //输出路径上的起点
                    Ppath(path, i, v);    //输出路径上的中间点
                    Console.WriteLine("{0}", i);    //输出路径上的终点
                }
                else 
                    Console.WriteLine("从{0}到{1}不存在路径\n", v, i);
            }
        }

        static void PutBothpath(MGraph g, int[] dist, int[] path, int[] s, int n, int v, int m)
        {
            int i;
            for (i = 0; i < n; i++)
            {
                if (s[i] == 1)
                {
                    //Console.Write(" 从{0}到{1}的最短路径长度为:{2}\t路径为:", v, i, dist[i]);
                    //Console.Write("{0},", v);    //输出路径上的起点
                    //Ppath(path, i, v);    //输出路径上的中间点
                    //Console.WriteLine("{0}", i);    //输出路径上的终点
                    if (i == m && dist[i] < INF)
                    {
                        Console.Write(" 从{0}到{1}的最短路径长度为:{2}\t路径为:", g.vexs[v].VexName, g.vexs[i].VexName, dist[i]);
                        Console.Write("{0},", g.vexs[v].VexName);    //输出路径上的起点
                        //Ppath(path, i, v);    //输出路径上的中间点
                        Ppath(g, path, i, v);
                        Console.WriteLine("{0}", g.vexs[i].VexName);    //输出路径上的终点
                    }
                }
                else
                    Console.WriteLine("从{0}到{1}不存在路径\n", v, i);
            }
        }

        static void Dijkstra(MGraph g, int v)
        {
            int[] dist = new int[MAXV];//从原点v到其他的各定点当前的最短路径长度
            int[] path = new int[MAXV];//path[i]表示从原点到定点i之间最短路径的前驱节点
            int[] s = new int[MAXV];   //选定的顶点的集合
            int mindis, i, j, u;
            u = 0;
            for (i = 0; i < g.n; i++)
            {
                dist[i] = g.edges[v, i];       //距离初始化
                s[i] = 0;                        //s[]置空  0表示i不在s集合中
                if (g.edges[v, i] < INF)        //路径初始化
                    path[i] = v;
                else
                    path[i] = -1;
            }
            s[v] = 1;                  //源点编号v放入s中
            path[v] = 0;                
            for (i = 0; i < g.n; i++)                //循环直到所有顶点的最短路径都求出
            {
                mindis = INF;                    //mindis置最小长度初值
                for (j = 0; j < g.n; j++)         //选取不在s中且具有最小距离的顶点u
                    if (s[j] == 0 && dist[j] < mindis)
                    {
                        u = j;
                        mindis = dist[j];
                    }
                s[u] = 1;                       //顶点u加入s中
                for (j = 0; j < g.n; j++)         //修改不在s中的顶点的距离
                    if (s[j] == 0)
                        if (g.edges[u, j] < INF && dist[u] + g.edges[u, j] < dist[j])
                        {
                            dist[j] = dist[u] + g.edges[u, j];
                            path[j] = u;
                        }
            }
           Dispath(dist, path, s, g.n, v);      //输出最短路径
           //PutBothpath(g, dist, path, s, g.n, v, 3);
        }

        static void initdata()
        {
            int i, j;
            MGraph g;
            g.n = 4; g.e = 8;
            g.edges = new int[MAXV, MAXV];
            g.vexs = new VertexType[MAXV];
            //int [,] anArray = new int [2, 4] {{1,2,3,4},{5,6,7,8}};
            int[,] a = new int[MAXV, MAXV] {
            {0,  5,INF,7},
            {INF,0,  4,2},
            {3,  3,  0,2},
            {INF,INF,1,0}
            };

            for (i = 0; i < g.n; i++)        //建立图的图的邻接矩阵
            {
                for (j = 0; j < g.n; j++)
                {
                    g.edges[i, j] = a[i, j];///////////////////////////////////////////////
                }
            }
            Console.WriteLine("各顶点的最短路径:");
        }

        static void initialVexInfo(MGraph g)
        {
            g.vexs[0].VexNo = "0361";
            g.vexs[0].VexName = "西安";

            g.vexs[1].VexNo = "010";
            g.vexs[1].VexName = "北京";

            g.vexs[2].VexNo = "0681";
            g.vexs[2].VexName = "武汉";

            g.vexs[3].VexNo = "0571";
            g.vexs[3].VexName = "杭州";
        }
        static void Main(string[] args)
        {
            int i, j;
            MGraph g;
            g.n = 4; g.e = 8;
            g.edges = new int[MAXV, MAXV];
            g.vexs = new VertexType[MAXV];

            initialVexInfo(g);
            //int [,] anArray = new int [2, 4] {{1,2,3,4},{5,6,7,8}};
            int[,] a = new int[MAXV, MAXV] {
            {0, 5,INF,7},
            {5, 0,  4,1},
            {INF, 4, 0,INF},
            {7,1,INF,0}
            };

            for (i = 0; i < g.n; i++)        //建立图的图的邻接矩阵
            {
                for (j = 0; j < g.n; j++)
                {
                    g.edges[i, j] = a[i, j];
                }
            }
            Console.WriteLine("最小生成树构成:");
            Dijkstra(g, 0);

            Console.ReadKey();
        }
    }
}

最短路径及其算法和ArcGIS放射状流向地图

该代码摘自博客园,有兴趣的同学可深入理解!!

最短路径及其算法和ArcGIS放射状流向地图

        2.ArcGIS放射状流向地图

最短路径及其算法和ArcGIS放射状流向地图

 Flow maps - show the movement of some phenomenon, normally goods or people, from one place to another. Lines are used to symbolize the flow, typically varied in width to represent differences in the quantity of the flow.

最短路径及其算法和ArcGIS放射状流向地图
最短路径及其算法和ArcGIS放射状流向地图


      放射状流向地图(Radial Flow Map):当事物或人从一个地点移动到另一个地点时,可以通过流向地图(Flow Maps)揭示出运动中的一些规律或现象。通常使用“线”来表示流向,且不同的宽度代表不同数量间的差异。它的特点就在于展示移动的地理现象,利用线的粗细或是颜色来展示更多的信息。它以特殊的可视化形式,直观地展示事物之间的联系,尤其在展示网络流向、贸易流向、迁徙路线等方面具有天然的优势。

下面我们来看看ArcGIS怎样能够快速的实现一幅放射状流向地图的制作。

具体步骤:

1.数据准备:XY to line工具所需要的输入是一个表格数据(.xls,.csv,.txt,.dbf均可以),必需的四个字段是每个点对的XY起止坐标,如下图所示,XCoor为各首都的X坐标,YCoord为各首都的Y坐标,BJX为北京的X坐标,BJY为北京的Y坐标,例如这里采用的是WGS 1984的坐标系统。

最短路径及其算法和ArcGIS放射状流向地图

    图5 放射性流向地图需要的表格内容

2.数据处理:打开XY to line工具,设置如图6,在Line Type中有四个选项,这里我们选择的是GEODISIC,ID字段设置为大洲,目的是为了保留该字段,以便将来按大洲进行符号化。

最短路径及其算法和ArcGIS放射状流向地图

              图6  XY TO Line


GEODESIC:测地线,椭球体表面上两点之间的最短连线。

GREAT_CIRCLE: 大圆航线,通过两航路点间的大圆圈线(该两航路点与地心在同一平面)。

RHUMB_LINE(loxodrome line): 等角航线:是地球表面上与经线相交成相同角度的曲线。在地球表面上除经线和纬线以外的等角航线,都是以极点为渐近点的螺旋曲线,在航海图(采用墨卡托投影)上又表现为直线。

NORMAL_SECTION:法截弧,A点的法线与B点确定的法截面与椭球相交的弧线。

经过简单渲染,我们就得到了这样的地图:

最短路径及其算法和ArcGIS放射状流向地图

                           图7

我们把图层属性或坐标系统换一种方式渲染得到下面另一种效果,如图9.

最短路径及其算法和ArcGIS放射状流向地图

                         图8

最短路径及其算法和ArcGIS放射状流向地图

                      图9  效果图

问题


  1. 流向地图有哪些类型?

    答:

    (一)网络流图:显示地点之间相互的连接,通常是基于交通或通讯联系。

最短路径及其算法和ArcGIS放射状流向地图

【示例】:美国俄勒冈州的公路交通情况。

(二)径向流图:轮辐状的形状,由一个共同的起源点或目的点作为各种要素和位置的结点绘制的地图。

最短路径及其算法和ArcGIS放射状流向地图

【示例】:2011年Esri美国用户大会参会者来源情况。


(三)分配流图:显示物品的分配流向,或从一个或几个起源地到多个目的地的扩散流向。

最短路径及其算法和ArcGIS放射状流向地图

(四)(点)矢量流图:使用欧几里得矢量数据(具有大小和方向的点位置),在空间和时间上显示连续变化的现象。

最短路径及其算法和ArcGIS放射状流向地图

参考

Esri中国——绘制流向地图

博客园——GIS Change Our Life及最短路径

最短路径及其算法和ArcGIS放射状流向地图

欢迎大家批评指正!!

最短路径及其算法和ArcGIS放射状流向地图

 投稿、编辑:吴春芽  吴峰平 

            校对:谢妙竹

            审核:郭锐涛

            指导:刘涛教授


以上是关于最短路径及其算法和ArcGIS放射状流向地图的主要内容,如果未能解决你的问题,请参考以下文章

算法笔记-最短路径规划

最短路必须通过两个指定点的最短路径算法及其matlab实现

最短路求两点间最短路的Floyd算法及其matlab实现

最短路求两点间最短路径的改进的Dijkstra算法及其matlab实现

核心算法8最短路径问题

最短路径 Dijkstra 算法为啥边上的权值非负阿?