最短路径之Dijkstra算法

Dijkstra算法:
首先。引进一个辅助向量D。它的每一个分量D[i]表示当前所找到的从始点v到每一个终点vi的的长度:如D[3]=2表示从始点v到终点3的路径相对最小长度为2。这里强调相对就是说在算法过程中D的值是在不断逼近终于结果但在过程中不一定就等于长度。

它的初始状态为:若从v到vi有弧,则D为弧上的权值;否则置D为∞。显然,长度为 D[j]=Min{D | vi∈V} 的路径就是从v出发的长度最短的一条。此路径为(v,vj)。 那么,下一条长度次短的是哪一条呢?如果该次短路径的终点是vk。则可想而知。这条路径或者是(v,vk),或者是(v,vj,vk)。它的长度或者是从v到vk的弧上的权值,或者是D[j]和从vj到vk的弧上的权值之和。

普通情况下,如果S为已求得的终点的集合,则可证明:下一条最短路径(设其终点为X)或者是弧(v,x),或者是中间仅仅经过S中的顶点而最后到达顶点X的路径。

因此,下一条长度次短的的长度必是D[j]=Min{D | vi∈V-S} 当中,D或者是弧(v,vi)上的权值,或者是D[k](vk∈S)和弧(vk,vi)上的权值之和。

算法描写叙述例如以下:
1)arcs表示弧上的权值。若不存在,则置arcs为∞(在本程序中为MAXCOST)。S为已找到从v出发的的终点的集合,初始状态为空集。那么,从v出发到图上其余各顶点vi可能达到的度的初值为D=arcs[Locate Vex(G,v),i] vi∈V
2)选择vj,使得D[j]=Min{D | vi∈V-S} 3)改动从v出发到集合V-S上任一顶点vk可达的最短路径长度。

考虑例如以下无向网(如果从v0出发):


最短路径数组变化情况:


最初。v0能到达的点为v2,v4,v5,距离分别为10,30,100,到其余点的距离默觉得无穷大(max),
然后。取最小权10,纳入S集。即v2点。又v2能够到达v3。距离为50。则v0->v3的距离可为10+50=60,小于当前的值(max),故更新辅助数组。紧接着,再取出一个最小权30(去掉之前的10),即v4,又v4能够到达v3,v5,距离分别为20,60,则v0->v3,v0->v5的距离能够分别为30+20=50,30+60=90,小于眼下的值60,100,故而继续更新辅助数组。以此类推。终于得到一个最短路径数组。

实现:
/**************************************
迪杰斯特拉算法求最短路径
by Rowandjj
2014/7/10
**************************************/

#include<iostream>
using namespace std;


#define INFINTY 65535
#define MAX_INFO 20
#define MAX_VERTEX_NUM 20

typedef int PathMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM];
typedef int ShortPathTable[MAX_VERTEX_NUM];


typedef struct _ARC_
{
    int adj;//顶点关系类型
    char *info;
}AdiMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM];

typedef struct _GRAPH_//图的邻接矩阵存储形式
{
    char vexs[MAX_VERTEX_NUM];
    AdiMatrix arcs;
    int arcnum,vexnum;
}Graph;
//-----------------------
int LocateVex(Graph G,char u);
void CreateDN(Graph *G);
void Display(Graph G);

void ShortestPath_DIJ(Graph G,int v0,PathMatrix *P,ShortPathTable *D);
//---------------------------------------------
int main()
{
    Graph g;
    CreateDN(&g);
    Display(g);

    PathMatrix p;
    ShortPathTable d;
    ShortestPath_DIJ(g,0,&p,&d);
    int i,j;
    printf("最短路径数组p[i][j]例如以下:\n");
    for(i=0;i<g.vexnum;++i)
    {
        for(j=0;j<g.vexnum;++j)
            cout<<p[i][j]<<"\t";
        cout<<endl;
    }
    cout<<"到各顶点的最短路径长度为:"<<endl;
    for(i=1;i<g.vexnum;++i)
        cout<<g.vexs[0]<<"-->"<<g.vexs[i]<<":"<<d[i]<<endl;
    return 0;
}

//--------------------------------------------
int LocateVex(Graph G,char u)
{
    int i = 0;
    for(i = 0; i < G.vexnum;i++)
    {
        if(u == G.vexs[i])
        {
            return i;
        }
    }
    return -1;
}
void CreateDN(Graph *G)//构建有向网
{
    int incInfo;
    int i,j,k,l,w;
    char s[MAX_INFO];
    cout<<"请输入有向网G的顶点数,弧数,弧是否含其他信息(是:1,否:0)"<<endl;
    cin>>G->vexnum;
    cin>>G->arcnum;
    cin>>incInfo;
    char va,vb;//分别代表弧头、弧尾
    char *pInfo;
    
    cout<<"请输入顶点值"<<endl;
    for(i = 0; i < G->vexnum; i++)
    {
        cin>>G->vexs[i];
    }
    for(i = 0; i < G->vexnum; i++)
    {
        for(j = 0; j < G->vexnum; j++)
        {
            G->arcs[i][j].adj = INFINTY;//网
            G->arcs[i][j].info = NULL;
        }
    }
    
    cout<<"请输入弧尾、弧头、权值"<<endl;
    for(k = 0; k < G->arcnum; k++)
    {
   
        cin>>va;
        cin>>vb;
        cin>>w;
        i = LocateVex(*G,va);
        j = LocateVex(*G,vb);
        
        G->arcs[i][j].adj = w;
        if(incInfo)
        {
            cout<<"请输入该弧的信息"<<endl;
            cin>>s;
            l = strlen(s);
            if(l)
            {
                pInfo = (char *)malloc(sizeof(char)*(l+1));
                strcpy(pInfo,s);
                G->arcs[i][j].info = pInfo;
            }
        }
        
    }
}

void Display(Graph G)
{
    int i,j;
    for(i = 0; i < G.vexnum; i++)
    {
        for(j = 0; j < G.vexnum; j++)
        {
            cout<<G.arcs[i][j].adj<<"\t";
        }
        cout<<endl;
    }
    cout<<endl;
}

void ShortestPath_DIJ(Graph G,int v0,PathMatrix *P,ShortPathTable *D)
{
    int v,w,i,j,min;
    int final[MAX_VERTEX_NUM];
    for(v=0;v<G.vexnum;++v)
    {
        final[v]=0;
        (*D)[v]=G.arcs[v0][v].adj;
        for(w=0;w<G.vexnum;++w)
            (*P)[v][w]=0; /* 设空路径 */
        if((*D)[v]<INFINTY)
        {
            (*P)[v][v0]=1;
            (*P)[v][v]=1;
        }
    }
    (*D)[v0]=0;
    final[v0]=1; /* 初始化,v0顶点属于S集 */
    
    for(i=1;i<G.vexnum;++i) /* 其余G.vexnum-1个顶点 */
    { /* 開始主循环,每次求得v0到某个v顶点的最短路径,并加v到S集 */
        min=INFINTY; /* 当前所知离v0顶点的近期距离 */
        for(w=0;w<G.vexnum;++w)
        {
            if(!final[w]) /* w顶点在V-S中 */
            {
                if((*D)[w]<min)
                {
                    v=w;
                    min=(*D)[w];
                } /* w顶点离v0顶点更近 */
            }        
        }
        
        final[v]=1; /* 离v0顶点近期的v增加S集 */
        for(w=0;w<G.vexnum;++w) /* 更新当前最短路径及距离 */
        {
            if(!final[w]&&min<INFINTY&&G.arcs[v][w].adj<INFINTY&&(min+G.arcs[v][w].adj<(*D)[w]))
            { /* 改动D[w]和P[w],w∈V-S */
                (*D)[w]=min+G.arcs[v][w].adj;
                for(j=0;j<G.vexnum;++j)
                    (*P)[w][j]=(*P)[v][j];
                (*P)[w][w]=1;
            }
        }
   }
}

測试:



转载于:https://www.cnblogs.com/ycfenxi/p/6718702.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值