最短路——dijkstra

原创 2015年07月10日 19:31:10

                                                                          


                                最短路——dijkstra

     


          这次写一下我用dijkstra算法做单源最短路的经历。

 

          首先先引入一个问题:给你两个数 m,n。n代表一共有n个村庄。之后有m行,每行包含三个数 from,to,dist.这三个数代表着,从村庄from到村庄to有dist 这么长的距离,此为无向图。

          现在想知道从村庄1到村庄n的最短的路径是多少。


          相关题目 here   http://poj.org/problem?id=2387 


          首先写的是很朴素的dijkstra算法:用邻接矩阵(二维数组)存图,外层for 1->n; 然后先找出dist[] 数组里面最小的一个数的编号(代表从目的地到这个编号的村庄的最短距离)。这个编号里的值此时已经可以确定是从出发点到这个这个编号的最短路径。然后在用一个for-1>n;通过这个最短距离,来改变其他村庄到出发点的距离。


          这便是dijkstra算法的核心思想,后面的优化只是优化的数据结构,对思想并未优化。

            

           初始有一个dist[]数组存放从起点到任一点的初始距离。


          举个简单的例子,已经确定从村庄1到村庄2的最短距离是100,已知从村庄2到村庄3的距离是100,从村庄1到村庄3的距离是500;

那么就可以用从 1->2->3(200) 来改变从 1->3(500)  的距离,此时被称为松弛边。但是如果1->2>3 大于 1->3的距离时,这个边就不必松弛。

        

          直接看代码吧:

          

               

<strong>#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<queue>
using namespace std;
const int inf=0x3f3f3f3f; //最大值,即1061109567
int main()
{
    int m,n;
    while(~scanf("%d%d",&m,&n))
    {
        int fro,to,d;
        int a[n+2][n+2]; //邻接矩阵存图
        int dist[n+2],vist[n+2];
        memset(a,inf,sizeof(a));  //inf可用memset
        memset(vist,0,sizeof(vist));
        memset(dist,inf,sizeof(dist));
        dist[1]=0;
        for(int i=0; i<m; i++)
        {
            scanf("%d%d%d",&fro,&to,&d);
            a[fro][to]=a[to][fro]=min(d,a[to][fro]);
        }
        for(int i=1; i<=n; i++)
        {
            int max1=inf;
            int x;
            //找到最短的一条路径来松弛其他的边
            for(int y=1; y<=n; y++)
                if(!vist[y]&&dist[y]<=max1)
                    max1=dist[x=y];
            vist[x]=1;//标记已经找到了从出发点到编号x的最短路,下次不再访问·
            for(int y=1; y<=n; y++)
            {//松弛边操作
                if(!vist[y]&&dist[y]>dist[x]+a[x][y])
                    dist[y]=dist[x]+a[x][y];
            }
        }
        printf("%d\n",dist[n]);
    }
}</strong>


              然后看到书上说可以用优先队列,来找到最短的那一条路。优先队列:即一个队列,在入队的同时其内部进行自动排序操作,可指定优先级,此处以小值优先的方式找到dist[]数组中的最小值。


         

#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<queue>
using namespace std;
const int inf=0x3f3f3f3f;
struct node
{
    //dis指dist[]数组中的距离,num指村庄编号
    int dis,num;
    //构造函数,便于赋初值
    node(int dis1,int num1):dis(dis1),num(num1) {}
    //指定优先级,以小值优先
    bool operator < (const node &a) const
    {
        return dis>a.dis;
    }
};
int a[1003][1006];
int vist[100000];
int d[100000];
int main()
{
    int n,m;

    while(~scanf("%d%d",&m,&n))
    {
        int fro,to,w;
        priority_queue<node> q;

        memset(a,inf,sizeof(a));
        memset(vist,0,sizeof(vist));
        memset(d,inf,sizeof(d));
        d[1]=0;
        for(int i=0; i<m; i++)
        {
            scanf("%d%d%d",&fro,&to,&w);
            //去重边
            a[fro][to]=a[to][fro]=min(w,a[to][fro]);
        }
        //将dist[1]的内容用node结构体存储并压进优先队列
        q.push(node(0,1));
        
        while(!q.empty())
        {
           node tmp=q.top();
           q.pop();
           //int u代指第一个的代码中的x,即有最小路径的那个编号
            int u=tmp.num;
           if(vist[u]) continue;
           vist[u]=1;
           for(int i=1;i<=n;i++)
           {
               if(d[i]>d[u]+a[i][u])
               {
                   d[i]=d[u]+a[i][u];
                   q.push(node(d[i],i));
               }
           }
        }
        printf("%d\n",d[n]);
    }
}


          但是上面的也有缺陷,那就是存储的图太小了,最多只能存储一千多个村庄之间的相互关系,如a[1005][1005];而如果遇到稀疏图的话,就太浪费空间与时间了。于是下面再写一个用vector数组模拟邻接表来存储图的dijkstra算法。

           vector:可动态分配空间,被称为动态数组;定义它vector<int> G.有三种主要操作方式:1):G.clear();//清空   2)G.size();//表长    3)G.push_back();//向表尾添加元素



         下面给出代码:


         

#include <iostream>
#include <vector>
#include <cstring>
#include<stdio.h>
#include<queue>
#include <algorithm>
using namespace std;
const int inf=0x3f3f3f3f;
const int MAX=10000;
struct edge  //存边
{
    int to,dist;
    //构造函数,可以赋初值
    edge(int to1=0,int dist1=0):to(to1),dist(dist1) {}
};
struct node  //入队列
{
    int num,dist;
    node(int num1=0,int dist1=0):num(num1),dist(dist1) {}
    bool operator < (const node &a) const
    {
        return dist>a.dist;
    }
};
vector<edge> G[MAX];
inline void addedge(int fro,int to, int dis)
{
    //无向图,有向图则舍弃第二语句
    G[fro].push_back(edge(to,dis));
    G[to].push_back(edge(fro,dis));
}
int m,n;

int vist[MAX],dist[MAX];

void dijkstra(int start)
{
    for(int i=1; i<=n; i++)
    {
        dist[i]=inf;
        vist[i]=0;
    }
    dist[start]=0;
    priority_queue<node>q;
    q.push(node(start,0));
    node tmp;
    while(!q.empty())
    {
        tmp=q.top();
        q.pop();
         //u代指第一个的代码中的x,即有最小路径的那个编号
        int u=tmp.num;

        //标记已经找到了从出发点到编号x的最短路,下次不再访问·
        if(vist[u]) continue;
        vist[u]=1;
        //村庄u的最短路已经找到,下面来松弛能通过u村庄来优化的边
        for(int i=0; i<G[u].size(); i++)
        {
            //用ff来减少代码复杂度
            edge &ff=G[u][i];

            if(dist[ff.to]>dist[u]+ff.dist)
            {
                dist[ff.to]=dist[u]+ff.dist;
                q.push(node(ff.to,dist[ff.to]));
            }
        }
    }
}

int A[MAX],B[MAX],C[MAX];
int main()
{
    while(scanf("%d%d",&m,&n)!=EOF)
    {
        for(int i=0;i<=n;i++)
            G[i].clear();  //必须要使用清空函数,因为有循环且是全局变量。
        for(int i=0; i<m; i++)
            scanf("%d%d%d",&A[i],&B[i],&C[i]);
            //存入邻接表中
        for(int i=0; i<m; i++)
            addedge(A[i],B[i],C[i]);

        //起点是一
        dijkstra(1);

        printf("%d\n",dist[n]);
    }
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

最短路(Dijkstra)

算法过程 1.设置顶点集合S并不断的作贪心选择来选择扩充这个集合。一个顶点属于集合S当且仅当从源点到该点的最短路径长度已知 2.初始时,S中仅含有源。设U是G的某一个顶点,把从源到U且中间只经过S中的...
  • booyoungxu
  • booyoungxu
  • 2015年07月28日 18:52
  • 1275

最短路算法详解(Dijkstra/SPFA/Floyd)

常用的图论最短路算法详解(dijkstra/SPFA/floyd)
  • murmured
  • murmured
  • 2014年02月16日 13:08
  • 2702

dijkstra求最短路并记录路径

图中通过path数组来记录路径,path[i]=j表明节点i取得最小路径时,其最后一段走的是节点j到节点i。 你也许会疑惑,我想知道的是整个路径呀,记录其中的最后一段有什么用呢? 我们这样来看,pat...
  • jinixin
  • jinixin
  • 2016年08月21日 18:02
  • 3110

[图论]最短路问题 dijkstra算法

今天研究的是图论中的一类基础问题:最短路问题 最短路问题是图论中最基础的问题,在程序设计竞赛试题中也经常出现。最短路是给定两个定点,在以这两个点为起点和终点的路径中,边的权值和最小的路径。如...
  • u012848631
  • u012848631
  • 2015年05月13日 13:16
  • 1421

最短路模板(dijkstra+邻接表)

#include #include #include #include #include #include #include #include #include using namespace std...
  • u013712847
  • u013712847
  • 2014年07月23日 20:41
  • 924

Dijkstra求最短路的条数,并输出最短路径和最短路经过的点的最大和

#include #include #include #include #include using namespace std; const int maxn=1e3; const...
  • alusang
  • alusang
  • 2017年11月26日 15:57
  • 164

图论:最短路问题 Floyd Dijkstra SPFA算法

昨天的模拟赛中有一道用到最短路算法的题,自己竟然写T了,所以今天来温习一下三个最短路算法,把模板写一写。  首先说明,这三个算法都是无向图有向图皆适用的。 Floyd算法: 三个里面最好写的算法,...
  • qq_25978793
  • qq_25978793
  • 2015年08月27日 15:32
  • 735

图论最短路之Dijkstra算法,SPFA算法

一.最短路径的最优子结构性质(转载 原文链接http://www.cnblogs.com/dolphin0520/archive/2011/08/26/2155202.html)   该性质描述为:...
  • mr_zj_
  • mr_zj_
  • 2016年07月13日 14:26
  • 1107

十二、图的算法入门--(4)最短路问题---Dijkstra算法实现

摘自计蒜客:http://www.jisuanke.com/course/35/7557 先来看这样一个问题:有n座城市,已知任意两个座城市之间的距离,现在要分别求出城市A到其他n-1座城市的最短路径...
  • firetreeSF
  • firetreeSF
  • 2016年05月09日 16:25
  • 2212

图算法系列之最短路算法Dijkstra(Java)

引言 假如你有一张地图,地图上给出了每一对相邻城市的距离,从一个地点到另外一个地点,如何找到一条最短的路? 最短路算法要解决的就是这类问题。今年的华为精英挑战赛codeCraft中关于部署大数据下网络...
  • xqhadoop
  • xqhadoop
  • 2017年04月08日 22:06
  • 591
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:最短路——dijkstra
举报原因:
原因补充:

(最多只允许输入30个字)