最短路径问题

最短路径问题

题目大意:
有A、B、C、D、E、F六个地方,A到B用时12,B到C用时10,C到D用时3,D到E用时4,E到F用时2,F到A用时16,B到F用时7,C到E用时5,C到F用时6,要求输入两个地方,求最短用时,以及路径。
测试用例举例
输入:C E(以空格分开)
输出:

5
C E

用Dijkstra 算法求解:

  • 算法思路
    Dijkstra算法输入加权有向图G和源点s,获得到其他所有顶点之间的最短路径距离。
    此外,需要集合S,其包含N个布尔值,用来记录已求出最短路径的顶点;集合U,用来记录还未求出最短距离的顶点;集合distance,用来记录到各顶点距离;集合prenode,记录最短路径中各顶点的父节点。
  • 流程
    1、初始时,S只包含起点s,U包含除s外的所有顶点,初始距离distance和prenode,未知父节点用-1表示;
    2、从U中选出“距离最短的顶点K”,并将K加入到S中,同时从U中删除K;
    3、更新distance,更新prenode
    4、重复(2)(3),直到遍历完所有顶点。

实现

代码核心参考https://blog.youkuaiyun.com/doufei_ccst/article/details/7841311

#include <iostream>
#include <vector>
#include <stack>

using namespace std;
const int Max = 6;

int graph[][Max] = {                                      //定义有向图
              {0,12,INT_MAX,INT_MAX,INT_MAX,INT_MAX},
              {INT_MAX,0,10,INT_MAX,INT_MAX,7},
              {INT_MAX,INT_MAX,0,3,5,6},
              {INT_MAX,INT_MAX,INT_MAX,0,4,INT_MAX},
              {INT_MAX,INT_MAX,INT_MAX,INT_MAX,0,2},
              {16,INT_MAX,INT_MAX,INT_MAX,INT_MAX,0}

};

int scaner(char input)           //键盘输入ABCDEF转为数字012345
{
    int num;
    switch(input)
    {
        case 'A':
              num = 0;
              break;
        case 'B':
              num = 1;
              break;
        case 'C':
              num = 2;
              break;
        case 'D':
              num = 3;
              break;
        case 'E':
              num = 4;
              break;
        case 'F':
              num = 5;
              break;
        default :
              cout <<"your input is error"<<endl;
    }
    return num;
}

char numtochar(int input)          // 矩阵索引012345转为ABCDE
{
    char num;
    switch(input)
    {
        case 0:
              num = 'A';
              break;
        case 1:
              num = 'B';
              break;
        case 2:
              num = 'C';
              break;
        case 3:
              num = 'D';
              break;
        case 4:
              num = 'E';
              break;
        case 5:
              num = 'F';
              break;
        default :
              cout <<"your input is error! please input again, Note: case sensitive,just(ABCDEF)"<<endl;
    }
    return num;
}

void Dijkstra(const int numnode, const int startnode,int graph[][Max], int *distance,int *prenode)
/*节点数, 源节点, 有向图邻接矩阵, 源节点到达各个节点的距离, 各个节点的前一个节点*/
{
    vector<bool> isInS;                 //是否已经在S集合中
    isInS.reserve(0);
    isInS.assign(numnode, false);   //初始化,所有的节点都不在S集合中

    /*初始化distance和prenode数组*/
    for(int i =0; i < numnode; ++i)
    {
        distance[ i ] = graph[ startnode ][ i ];
        if(graph[ startnode ][ i ] < INT_MAX)
            prenode[ i ] = startnode;
        else
            prenode[ i ] = -1;       //表示还不知道前一个节点是什么
    }
    prenode[ startnode ] = -1;

    isInS[startnode] = true;          //开始节点放入S集合中

    int u = startnode;

    for (int i = 1; i < numnode; i ++)    //这里循环从1开始是因为开始节点已经存放在S中了,还有numnode-1个节点要处理
    {

        /*选择distance最小的一个节点*/
        int nextnode = u;
        int tempDistance = INT_MAX;
        for(int j = 0; j < numnode; ++j)
        {
            if((isInS[j] == false) && (distance[j] < tempDistance))     //寻找不在S集合中的distance最小的节点
            {
                nextnode = j;
                tempDistance = distance[j];
            }
        }
        isInS[nextnode] = true;    //放入S集合中
        u = nextnode;                  //下一次寻找的开始节点


        /*更新distance*/
        for (int j =0; j < numnode; j ++)
        {
            if (isInS[j] == false && graph[u][j] < INT_MAX)
            {
                int temp = distance[ u ] + graph[ u ][ j ];
                if (temp < distance[ j ])
                {
                    distance[ j ] = temp;
                    prenode[ j ] = u;
                }
            }
        }
    }
}


int main()
{
    int distance[Max];
    int prenode[Max];
    char inchar[4];
    cout <<"please input two char in {ABCDE}:";
L1: cin.get(inchar, 4).get();
    int startnode = scaner(inchar[0]);
    int endnode = scaner(inchar[2]);
    if(startnode<0 || startnode>5 || endnode<0 || endnode>5 )
    {
        goto L1;
    }

    Dijkstra(Max,startnode,graph, distance, prenode);

    cout << "the distance is: "<<distance[endnode]<<endl;
    cout <<"the trace is: ";
    int index = endnode;
    stack<int> trace;
    while(prenode[index] != -1)
    {
       trace.push(prenode[index]);
       index = prenode[index];
    }

    while(!trace.empty())
    {
        cout <<numtochar(trace.top())<<" ";
        trace.pop();
    }
    cout <<numtochar(endnode)<<endl;

    return 0;
}

结果

在这里插入图片描述

参考

1. https://blog.youkuaiyun.com/doufei_ccst/article/details/7841311
2. https://blog.youkuaiyun.com/heroacool/article/details/51014824

`

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值