最短路径—Dijkstra算法

Dijkstra算法


参考文档:http://www.cnblogs.com/xl1027515989/p/3605393.html

1.定义概览

Dijkstra(迪杰斯特拉)算法是典型的单源最短路径算法,用于计算一个节点到其他所有节点的最短路径。主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止。Dijkstra算法是很有代表性的最短路径算法,在很多专业课程中都作为基本内容有详细的介绍,如数据结构,图论,运筹学等等。注意该算法要求图中不存在负权边。

问题描述:在无向图 G=(V,E) 中,假设每条边 E[i] 的长度为 w[i],找到由顶点 V0 到其余各点的最短路径。(单源最短路径)

 

2.算法描述

1)算法思想:设G=(V,E)是一个带权有向图,把图中顶点集合V分成两组,第一组为已求出最短路径的顶点集合(用S表示,初始时S中只有一个源点,以后每求得一条最短路径 , 就将加入到集合S中,直到全部顶点都加入到S中,算法就结束了),第二组为其余未确定最短路径的顶点集合(用U表示),按最短路径长度的递增次序依次把第二组的顶点加入S中。在加入的过程中,总保持从源点v到S中各顶点的最短路径长度不大于从源点v到U中任何顶点的最短路径长度。此外,每个顶点对应一个距离,S中的顶点的距离就是从v到此顶点的最短路径长度,U中的顶点的距离,是从v到此顶点只包括S中的顶点为中间顶点的当前最短路径长度。

2)算法步骤:

a.初始时,S只包含源点,即S={v},v的距离为0。U包含除v外的其他顶点,即:U={其余顶点},若v与U中顶点u有边,则<u,v>正常有权值,若u不是v的出边邻接点,则<u,v>权值为∞。

b.从U中选取一个距离v最小的顶点k,把k,加入S中(该选定的距离就是v到k的最短路径长度)。

c.以k为新考虑的中间点,修改U中各顶点的距离;若从源点v到顶点u的距离(经过顶点k)比原来距离(不经过顶点k)短,则修改顶点u的距离值,修改后的距离值的顶点k的距离加上边上的权。

d.重复步骤b和c直到所有顶点都包含在S中。

 

执行动画过程如下图

 

模板:

const int  MAXINT = 32767;
const int MAXNUM = 10;
int dist[MAXNUM];

int map[MAXUNM][MAXNUM];

void Dijkstra(int v0)      //v0代表起点
{
    int vis[MAXNUM];                    // 判断是否已存入该点到S集合中
      int n=MAXNUM;
    for(int i=1; i<=n; ++i)
    {
        dist[i] = map[v0][i];
        vis[i] = 0;                                // 初始都未用过该点
     }
     dist[v0] = 0;
     vis[v0] = true;   
    for(int i=2; i<=n; i++)
    {
         int mindist = MAXINT;
         int u = v0;                               // 找出当前未使用的点j的dist[j]最小值
         for(int j=1; j<=n; ++j)
            if((!vis[j]) && dist[j]<mindist)
            {
                  u = j;                             // u保存当前邻接点中距离最小的点的号码 
                  mindist = dist[j];
            }
         vis[u] = 1; 
         for(int j=1; j<=n; j++)
             if((!vis[j]) && map[u][j]<MAXINT && dist[u] + A[u][j] < dist[j])
             {
                    dist[j] = dist[u] + A[u][j];    //更新dist 
              }
     }
}

4.算法实例

先给出一个无向图

用Dijkstra算法找出以A为起点的单源最短路径步骤如下

 

5.OJ实例


poj - 2387   http://blog.csdn.net/u011637069/article/details/38511753


#include <stdio.h>
#include <string.h>
#define INF 1000000

int map[1010][1010];
int d[1010],vis[1010];

void dij(int n)
{
    int i,j,k,v,min;
    memset(vis,0,sizeof(vis));
    for(i=1;i<=n;i++)
    {
        d[i]=map[1][i];
    }
    d[1]=0;
    vis[1]=1;
    for(i=2;i<=n;i++)
    {
        min = INF;
        for(j=1;j<=n;j++)
        {
            if((!vis[j]) && d[j]<min)
            {
                 min = d[j];
                 v = j;
            }
        }
        //printf("v=%d\n",v);
        vis[v] = 1;
        for(j=1;j<=n;j++)
        {
            if((!vis[j]) && (d[j]>d[v]+map[v][j]))
            d[j] = d[v]+map[v][j];
        }
        //for(j=1;j<=n;j++)
        //    printf("%d ",d[j]);
        //printf("\n");
    }
}

int main()
{
    int i,j,m,n,a,b,val;
    scanf("%d%d",&m,&n);
    for(i=1;i<=n;i++)
        for(j=1;j<=n;j++)
        map[i][j]=INF;
    for(i=1;i<=n;i++)
        d[i]=INF;
    for(i=0;i<m;i++)
    {
        scanf("%d%d%d",&a,&b,&val);
        if(val<map[a][b])
            map[a][b]=map[b][a]=val;
    }
    //for(i=1;i<=n;i++)
    //    for(j=1;j<=n;j++)
    //    printf("%d ",map[i][j]);
    dij(n);
    printf("%d\n",d[n]);
    return 0;
}
///AC 47MS
//最短路径—Dijkstra算法


poj - 1062     http://blog.csdn.net/u011637069/article/details/38512011


#include <stdio.h>
#include <string.h>
#define INF 0x7fffffff//无限大

int price[110][110],vis[110],d[110],lv[110];
     //物品i在有第t号替代品情况下的优惠价pricr[t][i],当t=0时说明i无替代品,此时为原价
int dij(int n)
{
    int i,j,v,mina;
    for(i=1;i<=n;i++)
        d[i]=price[0][i];
    for(i=1;i<=n;i++)
    {
        v = 0;
        mina = INF;
        for(j=1;j<=n;j++)
        {
            if(!vis[j] && mina>d[j])
            {
                mina = d[j];
                v = j;
            }
        }
        if(v==0)
            break;
        vis[v]=1;
        for(j=1;j<=n;j++)
        {
            if((!vis[j]) && (price[v][j]!=INF) && (d[j]>d[v]+price[v][j]))///必须要加上(price[v][j]!=INF)这一句否则越界
                d[j]=d[v]+price[v][j];
        }
    }
    //for(j=1;j<=n;j++)
    //    printf("%d ",d[i]);
    return d[1]; //返回当前次交易后目标点1在等级lv[i]约束下的最短距离
}
int main()
{
    int i,j,k,m,n,num;
    int t,u,maxlv,temp,minprice=INF;
    //printf("%d\n",INF);
    scanf("%d%d",&m,&n);
    memset(vis,0,sizeof(vis));
    memset(lv,0,sizeof(lv));
    for(i=0;i<=n;i++)
        for(j=0;j<=n;j++)
            price[i][j]=INF;
    for(i=0;i<=n;i++)
        d[i]=INF;
    for(i=1;i<=n;i++)
    {
        scanf("%d%d%d",&price[0][i],&lv[i],&num);//price[0][i]物品i无替代品时的原价
        for(j=1;j<=num;j++)
        {
            scanf("%d%d",&t,&u);
            price[t][i]=u;
        }
    }
    minprice = INF;
    for(i=1;i<=n;i++)
    {
        maxlv=lv[i];
        for(j=1;j<=n;j++)
        {
            if(lv[j]>maxlv || maxlv -lv[j]>m)
                vis[j]=1;
            else
                vis[j]=0;
        }

        temp = dij(n);
        //printf("%d\n",temp);
        if(minprice >temp)
            minprice = temp;
    }
    printf("%d\n",minprice);
    return 0;
}
//AC  C++ 0MS  204K
//<span style="font-size:18px;">dijkstra</span>算法


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值