求最短路径Dijkstra算法C++

我写的这个是错误的。才发现之前是自己理解错了,请不要参考。

不过可以作为错误样例参考。错误原因,第三步,对距离值进行修改,修改的是还未求出权值的顶点的最短路径,而不是已经求出权值的点。虽然最后实现的结果是对的,但因为这里弄错了一丁点,导致整个代码量加了很多。(当初理解错了这个算法,觉得这么做好幼稚,还默默地在心里鄙视过这个算法,渣渣的任性太可笑了)。本来想删了这篇,想想还是算了吧。权当一个不认真学习算法的教训的记录吧。




一个有向图,指定一个源点,求它到其他结点的最短路径。

算法步骤如下:
G={V,E}
1. 初始时令 S={V0},T=V-S={其余顶点},T中顶点对应的距离值
若存在<V0,Vi>,d(V0,Vi)为<V0,Vi>弧上的权值
若不存在<V0,Vi>,d(V0,Vi)为∞
2. 从T中选取一个与S中顶点有关联边且权值最小的顶点W,加入到S中
3. 对其余T中顶点的距离值进行修改:若加进W作中间顶点,从V0到Vi的距离值缩短,则修改此距离值
重复上述步骤2、3,直到S中包含所有顶点,即W=Vi为止
baidu百科给的思路,基本上按照这个步骤写的,首先找到所有能从源点直接到达的点,得到它们的最短路径。

重复操作:遍历所有和已经确定了最短路径的点相关联的路径,选出权值最小的路径,得到其对应的结点的最小路径值,然后再检查一下原有的结点,是否因为加入了新的结点,而多了一条更短的路径。

重复n-1次。(共n个点)

我这里直接定义一个固定大小的图,录入的图的结点也许只有几个,并未另外计算到底有几个结点,每次遍历的时候都全部遍历一遍,因为那些不存在的点初始的最小路径值都为无穷大(这里用999表示),最后输出只要是999的即为到达不了,不输出,不过这样做虽然不影响,但浪费了空间和时间。其实可以在录入数据之后,动态分配空间建立图。

#include <iostream>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define MAXNUM 9

int graph[MAXNUM][MAXNUM];
int D[MAXNUM];//用来存放到达对应顶点的最小路径
int final[MAXNUM];//用来标志是否已求出最短路径
int V0;

using namespace std;

void createGraph(int V1,int V2,int weight)//V1->V2
{
    graph[V1][V2]=weight;
}

void inputGraph()//将图的结点读入
{
    char ch;
    int V1,V2,weight;
    do
    {
        cin>>ch;
        if (ch!='#')
            V1=ch-'0';
        else break;
        cin>>V2;
        cin>>weight;
        createGraph(V1,V2,weight);
    }
    while (1);
}

int shortestPath(int Vj)//用来检查时判断是否某些点又有了更短的路径
{
    int i;
    int temp=999;
    for (i=0; i<MAXNUM; i++)
    {
        if ((graph[i][Vj]>0)&&(graph[i][Vj]+D[i]<temp))
            temp=graph[i][Vj]+D[i];
    }
    if (temp!=999) D[Vj]=temp;
    return temp;
}

void Dijkstra()
{
    int i,j,k,Va,Vb,temp;
    D[V0]=0;
    final[V0]=1;
    for (i=0; i<MAXNUM; i++)//找出所有从源点可直接到达的点,得到暂时的最小路径
    {
        if (i!=V0)
        {
            if (graph[V0][i]>0)
                D[i]=graph[V0][i];
            else
                D[i]=999;
        }

    }

    for (i=1; i<MAXNUM; i++) //重复n-1次
    {
        temp=999;
        for (j=0; j<MAXNUM; j++)
        {
            if (1==final[j])
            {
                for (k=0; k<MAXNUM; k++)
                {
                    if ((graph[j][k]>0)&&(0==final[k])&&(graph[j][k]<temp))
                    {
                        temp=graph[j][k];
                        Va=j;
                        Vb=k;
                    }
                }
            }
        }

        if (temp!=999)
        {
            final[Vb]=1;
            D[Vb]=temp;
        }
        //对已经确定的顶点再做修改
        for (j=0; j<MAXNUM; j++)
        {
            if (1==final[j])
            {
                shortestPath(j);
            }
        }
    }

}

void display()
{
    int i;
    cout<<"从"<<V0<<"出发,到达各点的最小路径为:"<<endl;
    for (i=0; i<MAXNUM; i++)
    {
        if (D[i]!=999)
            cout<<i<<":"<<D[i]<<endl;
    }
}

int main()
{

    cout<<"请输入各边的权值,以#结束:(格式:顶点1 顶点6 权值3),"<<endl;
    inputGraph();//将图的信息读入,创建图
    cout<<"请输入源点"<<endl;
    cin>>V0;
    Dijkstra();
    display();

    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值