每日一算法题-最短路径

149 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第28天,点击查看活动详情

一、题目

描述:
学校开学,就会迎来很多新生,新生对学校不熟悉,现在需要一个小程序来帮助这些新生熟悉我们学校的各个重要建筑。
给出n个建筑,并且给出每个建筑可以走的路径和路径的具体距离值,要求随机给出两个建筑,请输出两个建筑的最短路径。

route.png

#include <iostream>
#include <vector>
#include <limits>
using namespace std;

struct Node{
    inline Node(string name): name(name){}
    inline void append(size_t node, int num) { route.push_back(node); distance.push_back(num); }
    string name;
    vector<size_t> route;
    vector<int> distance;
};

vector<Node*> shortestDistanceRoute(vector<Node*>& nodes, size_t start, size_t end)
{
    
}

int main(int, char*[])
{
    vector<Node*> nodes;

    Node* node1 = new Node("二号门");
    Node* node2 = new Node("三号门");
    Node* node3 = new Node("共青团花园");
    Node* node4 = new Node("光大礼堂");
    Node* node5 = new Node("半月楼");
    Node* node6 = new Node("行署楼");
    Node* node7 = new Node("中心图书馆");
    Node* node8 = new Node("田家炳");
    Node* node9 = new Node("竹园");
    Node* node10 = new Node("橘园");

    nodes.push_back(node1);
    nodes.push_back(node2);
    nodes.push_back(node3);
    nodes.push_back(node4);
    nodes.push_back(node5);
    nodes.push_back(node6);
    nodes.push_back(node7);
    nodes.push_back(node8);
    nodes.push_back(node9);
    nodes.push_back(node10);

    node1->append(2, 350);
    node3->append(0, 350);
    node3->append(8, 600);
    node3->append(3, 800);
    node9->append(2, 600);
    node9->append(3, 800);
    node4->append(2, 800);
    node4->append(8, 800);
    node4->append(1, 400);
    node4->append(6, 150);
    node2->append(3, 400);
    node7->append(3, 150);
    node7->append(4, 200);
    node7->append(5, 550);
    node5->append(6, 200);
    node5->append(9, 450);
    node5->append(7, 500);
    node6->append(6, 550);
    node6->append(7, 200);
    node8->append(5, 200);
    node8->append(4, 500);
    node8->append(9, 400);
    node10->append(7, 400);
    node10->append(4, 450);

    for(Node* node : shortestDistanceRoute(nodes, 0, 3)){
        cout << node->name << "->";
    }
    cout << endl;

    return 0;
}

二、分析

由题意可知,要获取最短路径,最简单的方法就是穷举,然后取其中最近的一条。 由于整个路径构成了一张图,存在多个环,避免在穷举之时陷入死循环,我们需要一个状态量来做标志。 这时,我们便可以进行走动,从出发点开始,遍历可以走的每条路径,在走了一步之后,将这一步记录下来,在他的下一步遍历时,避免再走回来。 碰到终点后结束,记录下行走的路径和距离,和上一个路径做对比,第一次走就直接视为最短。 再行走途中,也可以动态比较已经走的距离和最短距离,如果已经超过最短距离,就代表此路过长,不用走了。 往回退时,需要把走的距离和地点删除,返回到原有的状态才能正确模拟。

三、模拟

  1. 二号门->共青团花园 350
  2. 共青团花园->竹园 950
  3. 竹园->光大礼堂 1750
  4. 共青团花园->光大礼堂 1150

四、实现

void dfs(vector<Node*>& nodes, vector<Node*>& result, bool* map, size_t start, size_t end, int& min, int cmin, vector<Node*>& current)
{
    if(start == end){
        if(cmin < min){
            min = cmin;
            result = current;
        }
    }else{
        if(map[start]) return;
        map[start] = true;
        for(size_t i = 0; i < nodes.at(start)->route.size(); ++i){
            size_t node = nodes.at(start)->route.at(i);
            cmin += nodes.at(start)->distance.at(i);
            current.push_back(nodes.at(start));
            dfs(nodes, result, map, node, end, min, cmin, current);
            current.pop_back();
            cmin -= nodes.at(start)->distance.at(i);
        }
        map[start] = false;
    }
}

vector<Node*> shortestDistanceRoute(vector<Node*>& nodes, size_t start, size_t end)
{
    vector<Node*> result;
    bool map[10] = {false};
    int min = std::numeric_limits<int>::max();
    vector<Node*> current;
    dfs(nodes, result, map, start, end, min, 0, current);
    result.push_back(nodes.at(end));
    return result;
}

五、结言

最短路径的解决办法有很多种,最简单的就是遍历,掌握好遍历的原理,才能更好的去优化。

创作不易,留个赞再走吧!如果对文章内容有任何指正,欢迎评论!