zoukankan      html  css  js  c++  java
  • 理解利用狄克斯特拉算法求最小生成树

    《数据结构》第8章 图 P222

    例8.8  利用狄克斯特拉算法求最小生成树

    首先说几个概念:

    1、在无向图G中,若从订单vi到顶点vj有路径,则称vi和vj是连通的。

    2、一个连通图的生成树是一个极小连通子图,它含有图中全部顶点,但只有构成一颗树的(n-1)条边。图的所有生成树中具有边上的权值之和最小的树称为图的最小生成树。

    3、在一个无权的图中,若从一顶点到另一顶点存在着一条路径,称该路径上所有经过的边的数目为该路径长度,它等于该路径上的顶点数减1。

        把路径长度最短的那条路径叫做最短路径。

    而狄克斯特拉算法就是求在一个图中,从指定顶点到其他顶点的最短路径。

    书中源代码:

    #include <stdio.h>
    #define MaxSize 100
    #define INF 32767 //INF表示∞
    #define MAXV 100 //最大顶点个数
    typedef int InfoType;

    typedef struct
    {
    int no; //顶点编号
    InfoType info; //顶点其他信息
    } VertexType; //顶点类型
    typedef struct //图的定义
    {
    int edges[MAXV][MAXV]; //邻接矩阵
    int n,e; //顶点数,弧数
    VertexType vexs[MAXV]; //存放顶点信息
    } MGraph; //图的邻接矩阵类型

    void Ppath(int path[],int i,int v) //前向递归查找路径上的顶点
    {
    int k;
    k=path[i];
    if (k==v) return; //找到了起点则返回
    Ppath(path,k,v); //找顶点k的前一个顶点
    printf("%d,",k); //输出顶点k
    }
    void Dispath(int dist[],int path[],int s[],int n,int v)
    {
    int i;
    for (i=0;i<n;i++)
    if (s[i]==1)
    {
    printf(" 从%d到%d的最短路径长度为:%d\t路径为:",v,i,dist[i]);
    printf("%d,",v); //输出路径上的起点
    Ppath(path,i,v); //输出路径上的中间点
    printf("%d\n",i); //输出路径上的终点
    }
    else printf("从%d到%d不存在路径\n",v,i);
    }
    void Dijkstra(MGraph g,int v) //狄克斯特拉算法
    {
    int dist[MAXV],path[MAXV];
    int s[MAXV];
    int mindis,i,j,u;
    for (i=0;i<g.n;i++)
    {
    dist[i]=g.edges[v][i]; //距离初始化
    s[i]=0; //s[]置空
    if (g.edges[v][i]<INF) //路径初始化
    path[i]=v;
    else
    path[i]=-1;
    }
    s[v]=1;path[v]=0; //源点编号v放入s中
    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); //输出最短路径
    }

    void main()
    {
    int i,j;
    MGraph g;
    g.n=7;g.e=12;
    int a[7][MAXV]={
    {0,4,6,6,INF,INF,INF},
    {INF,0,1,INF,7,INF,INF},
    {INF,INF,0,INF,6,4,INF},
    {INF,INF,2,0,INF,5,INF},
    {INF,INF,INF,INF,0,INF,6},
    {INF,INF,INF,INF,1,0,8},
    {INF,INF,INF,INF,INF,INF,0}};
    for (i=0;i<g.n;i++) //建立图9.16所示的图的邻接矩阵
    for (j=0;j<g.n;j++)
    g.edges[i][j]=a[i][j];
    printf("最短路径:\n");
        Dijkstra(g,0);
    printf("\n");
    }

    书上说:

    解 利用狄克斯特拉算法可以求出从指定顶点(源点)到其他顶点的最短路径,而最小生成树是以源点为根,其路径权值之和最小的生成树,因此,由源点到所有其他顶点的最短路径上的不重复出

    现的边构成了最小的生成树的所有边。

    具体代码:

    #include <stdio.h>
    #define MaxSize 100
    #define INF 32767 //INF表示∞
    #define MAXV 100 //最大顶点个数
    typedef int InfoType;

    typedef struct
    {
    int no; //顶点编号
    InfoType info; //顶点其他信息
    } VertexType; //顶点类型
    typedef struct //图的定义
    {
    int edges[MAXV][MAXV]; //邻接矩阵
    int n,e; //顶点数,弧数
    VertexType vexs[MAXV]; //存放顶点信息
    } MGraph; //图的邻接矩阵类型
    void DisMinTree(int path[],int s[],int n,int v)
    //由path求最小的生成树
    {
    int i,pre,j,k;
    int edges[MAXV][2],edgenum=0; //edges数组用于存放最小生成树的所有边,
    //edges[i][0]存放第i条边的起点,edges[i][1]存放第i条边的终点
    printf(" 最小生成树的所有边:\n\t");
    for (i=0;i<n;i++)
    if (s[i]==1 && i!=v)
    {
    j=i;
    pre=path[i];
    do //搜索最短路径生成最小生成树的所有边
    { if (edgenum==0) //将(pre,j)边加入到edges中
    { edges[edgenum][0]=pre;
    edges[edgenum][1]=j;
    edgenum++;
    }
    else
    {
    k=0;
    while (k<edgenum&&(edges[k][0]!=pre||edges[k][1]!=j))
    k++;
    if (k>=edgenum) //(pre,j)边未在edges中时加入
    {
    edges[edgenum][0]=pre;
    edges[edgenum][1]=j;
    edgenum++;
    }
    }
    j=pre;
    pre=path[pre];
    } while (pre!=v);
    }
    for (k=0;k<edgenum;k++)
    printf("(%d,%d) ",edges[k][0],edges[k][1]);
    printf("\n");
    }

    void Dijkstra(MGraph g,int v)
    {
    int dist[MAXV],path[MAXV];
    int s[MAXV];
    int mindis,i,j,u;
    for (i=0;i<g.n;i++)
    {
    dist[i]=g.edges[v][i]; //距离初始化
    s[i]=0; //s[]置空
    if (g.edges[v][i]<INF) //路径初始化
    path[i]=v;
    else
    path[i]=-1;
    }
    s[v]=1;path[v]=0; //源点编号v放入s中
    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;
    }
    }
    DisMinTree(path,s,g.n,v); //输出最小生成树
    }

    void main()
    {
    int i,j;
    MGraph g;
    g.n=7;g.e=12;
    int a[7][MAXV]={
    {0,4,6,6,INF,INF,INF},
    {INF,0,1,INF,7,INF,INF},
    {INF,INF,0,INF,6,4,INF},
    {INF,INF,2,0,INF,5,INF},
    {INF,INF,INF,INF,0,INF,6},
    {INF,INF,INF,INF,1,0,8},
    {INF,INF,INF,INF,INF,INF,0}};
    for (i=0;i<g.n;i++) //建立图9.16所示的图的邻接矩阵
    for (j=0;j<g.n;j++)
    g.edges[i][j]=a[i][j];
    Dijkstra(g,0);
    printf("\n");
    }

    个人感觉不太理解,然后想了想,觉得书上这样解释有点笼统,不易于理解,于是,自己把自己的理解写下来。

    假设有图G,其中有顶点A、B、C、D...,开始利用狄克斯特拉算法从顶点A开始查找最短路径,首先找到B,如下图1:

        图1

    然后,从【A-C:2】 【B-C:(无穷)】【A-D:1】【B-D:3】中查找权值最小的也就是A-D,这时我们可以把A、B(左圆)看成一个系统AB,然后AB到C的距离是2,到D的距离是1,

    所以得到图2:

        图2

    然后把D添加到左圆(已找到最短路径),如图3:

        图3

    然后得到系统ABD到C的距离是2,然后依次添加顶点,直到右圆为空,即所有顶点均已找到最短路径。

    以上就是狄克斯特拉算法求的从指定顶点(A)到其他顶点最短路径的算法,其实里面已经包含了求最小生成树的算法,为什么这样说呢,请看下面解释。

    图2中左圆也就是系统AB可以看成一个只有A和B两个顶点的图,那么AB也就是这个图的最小生成树了,然后现在又添加了顶点D(因为A-D、B-D和A-C中最短是A-D也就是顶点D),这时有两种选择

    A-D(1)和B-D(3),所以按照最小生成树法则,选择A-D(1)作为代表,代表系统(AB)和D的桥梁。这时形成图3,而系统AB也变成了系统ABD,而系统ABD同样还是一个只有三个顶点A、B和D的图的最小生成树,所以按照狄克斯特拉算法得到的就是指定图的最小生成树!

    是个人理解,可能有些愚钝,肯定有更好地理解方法,望大家指教!

    2012.02.21

    02 2012 档案
     
    (转)windows身份验证登入数据库 iis 无法访问数据库
    摘要: 原文地址:http://www.cnblogs.com/d-xtl/archive/2011/12/27/2303890.htmlSystem.Data.SqlClient.SqlException: 用户'pc-2009\ASPNET' 登录失败的解决办法今天发布网站的时候遇到这个问题,多方查询后终于找到答案!System.Data.SqlClient.SqlException: 用户'pc-2009\ASPNET' 登录失败的解决办法: (此处的PC-2009是我的机器名)由于他的数据库连接语句中没有采用用户名和密码验证,采用的是windows集成验证,所以阅读全文
    posted @ 2012-02-21 19:12 风筝blog 阅读(0) | 评论 (0) 编辑
     
    (转)SQL Server 2005 Express版、标准版,企业版,工作组版功能比较,不同区别
    摘要: 原文地址:http://hi.baidu.com/netkey/blog/item/a6f2b445cca7ab23cffca32e.html http://hi.baidu.com/netkey/blog/item/6c09bb0e6be37de236d1222e.htmlSQL Server 2005 Express版、标准版,企业版,工作组版功能比较,不同区别Microsoft 已重新设计了 SQL Server 2005 产品系列,有 Express、Workgroup、Standard 和 Enterprise 四种新版本,从而可以更好地满足各个客户领域的需求。与竞争性解...阅读全文
    posted @ 2012-02-21 15:46 风筝blog 阅读(5) | 评论 (0) 编辑
     
    风筝数据结构学习笔记(3)理解利用狄克斯特拉算法求最小生成树
    摘要: 《数据结构》第8章 图 P222例8.8 利用狄克斯特拉算法求最小生成树首先说几个概念:1、在无向图G中,若从订单vi到顶点vj有路径,则称vi和vj是连通的。2、一个连通图的生成树是一个极小连通子图,它含有图中全部顶点,但只有构成一颗树的(n-1)条边。图的所有生成树中具有边上的权值之和最小的树称为图的最小生成树。3、在一个无权的图中,若从一顶点到另一顶点存在着一条路径,称该路径上所有经过的边的数目为该路径长度,它等于该路径上的顶点数减1。 把路径长度最短的那条路径叫做最短路径。而狄克斯特拉算法就是求在一个图中,从指定顶点到其他顶点的最短路径。书中源代码:#include <stdio阅读全文
    posted @ 2012-02-21 13:50 风筝blog 阅读(368) | 评论 (1) 编辑
     
    微软数据访问应用程序块2.0
    摘要: 微软数据访问应用程序块(Microsoft Data Access Application Block):http://msdn.microsoft.com/zh-cn/library/aa480458.aspx2.0:Earlier Release: Data Access Application Block 2.0 (pre-Enterprise Library)2.0下载地址:http://www.microsoft.com/download/en/confirmation.aspx?id=4352.0中的sqlhelper:https://files.cnblogs.com/fiteg/阅读全文
    posted @ 2012-02-17 18:09 风筝blog 阅读(5) | 评论 (0) 编辑
     
    细细品味C#——抽象、接口、委托、反射(转)
    摘要: 原博文地址:http://www.cnblogs.com/xia520pi/archive/2011/10/07/2200793.html(*风筝注:因文章链接可能失效,特转发过来,避免以后丢失) 什么是抽象类?什么是接口?接口与抽象类有什么区别?什么是委托?什么是反射? 这些都是初学者比较犯糊涂的事情,呵呵,这个也不能说的太绝对,反正我就是那个糊涂中的一个。为了把这些最基本的概念和知识打扎实,我整理一下相关的知识点,希望对你也有帮助。 文章下载地址:https://files.cnblogs.com/fiteg/C_Sharp_FanShe.rar(*风筝已重新上传,更新地址) 文章的...阅读全文
    posted @ 2012-02-17 14:32 风筝blog 阅读(6) | 评论 (1) 编辑
     
    风筝数据结构学习笔记(2)后序遍历二叉树(非递归)
    摘要: 看书上的非递归遍历二叉树太难理解,自己想了这个算法,代码如下:void PostOrder1(BTNode * b){ BTNode * st[MaxSize]; BTNode *p, *old=b; int top=-1; top++; st[top]=b; while(top>-1) { p = st[top]; if((p->lchild == NULL && p->rchild == NULL )|| (p->lchild == old ||p->rchild == old)) { ...阅读全文
    posted @ 2012-02-16 16:20 风筝blog 阅读(3) | 评论 (0) 编辑
     
    风筝数据结构学习笔记(1)利用链式存储结构和递归构建二叉树
    摘要: 2012.02.16数据结构学习笔记(1)利用链式存储结构和递归构建二叉树书上是用循环实现,我写了用递归实现,代码如下: 1 #include <stdio.h> 2 #include <malloc.h> 3 #define MaxSize 100 4 typedef char ElemType; 5 typedef struct node 6 { 7 ElemType data; //数据元素 8 struct node *lchild; //指向左孩子结点 9 struct node *rchild; //指向右孩子结...阅读全文
    posted @ 2012-02-16 15:06 风筝blog 阅读(98) | 评论 (0) 编辑
     
    吕震宇老师《设计模式随笔系列》
    摘要: http://www.cnblogs.com/zhenyulu/category/15561.html阅读全文
    posted @ 2012-02-15 17:12 风筝blog 阅读(11) | 评论 (0) 编辑
     
    吕震宇老师《设计模式系列》
    摘要: http://www.cnblogs.com/zhenyulu/category/6930.html阅读全文
    posted @ 2012-02-15 17:03 风筝blog 阅读(7) | 评论 (0) 编辑
     
    C#测试程序运行时间(转)
    摘要: 测试程序运行时间(转)原文:http://www.cnblogs.com/kavilee/archive/2010/12/13/1904274.html一、用C#自带的StopWatch函数using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Diagnostics;namespace StopWatch{ class Program { static void Main(string[] args) { Stopwatch sw = new Stopwatc阅读全文
    posted @ 2012-02-07 16:54 风筝blog 阅读(6) | 评论 (0) 编辑
    01 2012 档案
     
    design principle:java 回调与委派/委托机制(转)
    摘要: design principle:java 回调与委派/委托机制原文地址:http://blog.csdn.net/AndroidBluetooth/article/details/6937468博客design principle:模拟 android Button 控件点击事件主要说了一下模拟 android 的 Listener 模式,其实这就是一种委派与回调机制的体现。委派,也可以叫做委托,从字面上来理解的话,应该是委托其他类做事情而自己不做或者只做一部分工作;而回调,就是调用自己的方法。在 java 中,这两种机制很类似,你姑且可以认为它们就是一码事。推荐一篇博文给大家:Java中委阅读全文
    posted @ 2012-01-31 11:35 风筝blog 阅读(20) | 评论 (0) 编辑
     
    Java中委托事件模型 (转)
    摘要: Java中委托事件模型原文地址:http://hbohuan.blog.163.com/blog/static/208489820077132225530/委托事件模型 —— Delegated Event Model或许每个软件从业者都有从学习控制台应用程序到学习可视化编程的转变过程,控制台应用程序的优点在于可以方便的练习某个语言的语法和开发习惯(如.net和java),而可视化编程的学习又可以非常方便开发出各类人机对话界面(HMI)。可视化编程或许是一个初学者开始对软件感兴趣的开始,也可能是一个软件学习的里程碑点,因为我们可以使用各类软件集成开发环境(IDE)方便的在现成的界面窗口上拖放各阅读全文
    posted @ 2012-01-31 11:26 风筝blog 阅读(11) | 评论 (0) 编辑
     
    对象可以访问类的私有成员(转)+自我理解
    摘要: 一个奇怪的发现:对象可以访问类的私有成员原文地址:http://blog.sina.com.cn/s/blog_4a8ed95f0100053d.htmlclass String{public:String& operator= (const String&str){//为什么在这里可以直接访问str对象的私有成员呢??size = str.size;}private:int size;};****************************************************网上答案:1。封装性是对类(不是对象)外的操作来说的。所以在类内操作本类的一个对象来说阅读全文
    posted @ 2012-01-31 10:09 风筝blog 阅读(821) | 评论 (3) 编辑
    2 2011 档案
     
    ASP.NET弹出对话框(转)
    摘要: 我们在.NET程序的开发过程中,常常需要和用户进行信息交互,比如执行某项操作是否成功,“确定”还是“取消”,以及选择“确定”或“取消”后是否需要跳转到某个页面等,下面是本人对常用对话框使用的小结,希望对大家有所帮助,同时也欢迎大家补充。 (1) 点击页面上的按钮,弹出一个对话框提示是“确定”还是“取消”操作,我们采用在按钮中添加属性来完成: 举例如下: public System.Web.UI.WebControls.Button btnDelRow; btnDelRow.Attributes.Add("onclick", "return confirm('阅读全文
    posted @ 2011-12-26 19:35 风筝blog 阅读(12) | 评论 (0) 编辑
     
    ASP.NET页面间数据传递的9种方法(转)
    摘要: 本文我们将讨论的是ASP.NET页面间数据传递的几种方法,对此希望能帮助大家正确的理解ASP.NET页面间数据传递的用处以及便利性。0、引言Web页面是无状态的, 服务器对每一次请求都认为来自不同用户,因此,变量的状态在连续对同一页面的多次请求之间或在页面跳转时不会被保留。在用ASP.NET 设计开发一个Web系统时, 遇到一个重要的问题是如何保证数据在页面间进行正确、安全和高效地传送,Asp.net 提供了状态管理等多种技术来解决保存和传递数据问题,以下来探讨.NET 下的解决此问题的各种方法和各自的适用场合。1、ASP.NET页面间数据传递的各种方法和分析1.1 使用Querystring阅读全文
    posted @ 2011-12-26 19:33 风筝blog 阅读(11) | 评论 (0) 编辑
     
    刚刚开通了博客,写点东西
    摘要: 看了以前的博客“最经典的实现字符数控制的方案哦!(完善版)”,虽然没有看懂,我也没有尝试,但是看到下面的评论,真的感触颇多。看到2005年的博客,那个时候的技术当然没有现在(2011)发达,也没有现在的技术五花八门,可是那个时候的程序员是真正的“程序员”!我看到下面的回复,几乎都是关于博客上论述的内容的,而且是真正的看了并且想了、试了,有许多提出各种各样的问题和bug,更多的是自己的想法、解决方法,楼主也是很真诚的一一回复解答,大家一起为了一件事情努力,我突然被这样一种精神感动了!真的,想想自己,也是80后的尾巴,看技术帖也不少,但真正的把帖上的内容看懂并且自己尝试着加以改变,几乎是没有~..阅读全文
    posted @ 2011-12-19 20:09 风筝blog 阅读(6) | 评论 (0) 编辑
  • 相关阅读:
    [TimLinux] CSS 纯CSS实现动画展开/收起功能
    [TimLinux] CSS pre超长自动换行
    j2ee之struts2表单细节处理
    j2ee之struts2的国际化数据方式
    j2ee之struts2拦截器()
    j2ee之struts2文件下载
    j2ee之struts2文件上传
    j2ee国际化数据方式
    j2ee监听器的实现及配置方法
    j2ee过滤器实现的主要代码
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/2361904.html
Copyright © 2011-2022 走看看