【总结笔记】最小生成树 Prime算法与单源最短路径 Dijkstra 算法 (C++ 优先队列)

最小生成树 Prime算法

参考链接:http://www.wutianqi.com/blog/1284.html
参考链接:https://blog.csdn.net/xinwen1995/article/details/51078211
参考链接:https://zhuanlan.zhihu.com/p/136387766

笔记 1:cmp 的书写:

struct cmp {
    bool operator()(pair<int, int> &a, pair<int, int> &b) {
        return a.second > b.second;   // 小根堆
    }
};

笔记 2:不定长二维数组的初始化

仅需定义最外层的大小即可,无边就不讲其加入到对应的 vector 容器

mat.resize(cityn);

笔记 3:判断结束条件是生成树中的结点计数

int cntCity = 0;
while (cntCity < cityn) {
  ...
  ++cntCity;
  ...
}

全部代码如下:

struct cmp {
    bool operator()(pair<int, int> &a, pair<int, int> &b) {
        return a.second > b.second;   // 小根堆
    }
};

class Solution {
public:
    priority_queue<pair<int, int>, vector<pair<int, int>>, cmp> prq;
    vector<vector<pair<int, int>>> mat;
    vector<int> visited;
    vector<int> dist;
    int totalCost = 0;
    int rootIdx = INT_MAX;
    int cntCity = 0;
    int getAnswer(int cityn, int edgen) {
        initAdj(cityn, edgen);
        prime(cityn);
        return totalCost;
    }
    void initAdj(int cityn, int edgen) {
        mat.resize(cityn);
        for (int i=0; i<edgen; ++i) {
            int src, des, w;
            cin >> src >> des >> w;
            // 由于输入范围是[1,n],而矩阵范围是[0, n-1]
            mat[src-1].emplace_back(make_pair(des-1, w));
            mat[des-1].emplace_back(make_pair(src-1, w));
            rootIdx = min(rootIdx, min(src-1, des-1));
        }
    }
    void prime(int cityn) {
        visited.resize(cityn, 0);
        dist.resize(cityn, INT_MAX);
        // 从 0 开始
        prq.emplace(make_pair(0, 0));
        while (cntCity < cityn) {
            pair<int, int> tmpPair = prq.top();
            prq.pop();
            int desCity = tmpPair.first, w = tmpPair.second;
            // 如果该最小边已经加入到生成树中,则跳过
            if (visited[desCity])
                continue;
            // 添加到生成树
            visited[desCity] = 1;
            dist[desCity] = 0;
            totalCost += w;
            ++cntCity;
            // 并将其所有未访问过的邻接边加入搜索空间范围
            for (auto &item : mat[desCity]) {
                int to = item.first, w = item.second;
                // 未访问限制 && 并且在搜索空间中,没有比它更优的边,就将其置入搜索空间
                if (!visited[to] && dist[to] > item.second) {
                    prq.emplace(item);
                    dist[to] = item.second;
                }
            }
        }
    }
};

int main()
{
    int cityn, edgen;
    cin >> cityn >> edgen;
    Solution* sol = new Solution();
    cout << sol->getAnswer(cityn, edgen);
}

//6 10
//1 2 6
//1 3 1
//1 4 5
//2 3 5
//2 5 3
//3 4 5
//3 5 6
//3 6 4
//4 6 2
//5 6 6

单源最短路径 Dijkstra 算法 (C++ 优先队列)

优先队列 priority_queue 需要导入 #include<queue>

参考链接:https://juejin.cn/post/6861787597388300296

时间限制: 3000MS
内存限制: 589824KB
题目描述:
最近DJI发布了一款Robomaster S1机器人,小伙伴们都沉迷其中不能自拔。小J为了能够在竞速比赛中迅速获胜,他决定利用开发的优势,在里面植入一套最优化的寻路算法。
比赛规则如下: 在比赛场地内预先设置N个路标,路标编号从0到N-1,S1只能沿直线在两个有连接的路标之间移动(部分路标之间是没有连接的) 比赛场地内的S1机器人从编号为0的路标出发,然后裁判给出随机一个路标(从0到N-1号路标中随机挑选一个)作为终点路标,要求S1机器人以尽可能快的速度从0号路标达到终点路标,总路程用时最短者获胜。
裁判会确保从0号路标和随机挑选的终点路标之间肯定存在至少一条路径。 小J在比赛开始前就已经得知了路标的数量 、通道的数量(每两个可以直接连接的路标点为一个通道)以及小车在每个通道上移动需要的时间。他需要编写一套算法,以确保能够快速找到最短路径,并输出小车在该路径移动所需要的时间,你能帮他实现这套算法吗?


输入描述
第一行输入两个个正整数 N和 P,其中N表示路标的数量, P表示通道的数量。 (1 < N <= 200,  0 <= P <= N * (N - 1) / 2 )
接下来的P行,每行输入三个正整数 A, B, T,A表示起点路标的编号,B表示终点路标的编号,T表示路标A到路标B需要时间T。 (0 <= A, B <= N-1, 1 <= T <= 100)
最后一行输入一个正整数 X,表示裁判给出的终点路标编号 (0 =< X <= N)
输出描述
输出一个正整数,表示小车从0号路标到X号路标之间移动的最短用时

样例输入
4 5
0 1 15
1 2 15
0 3 50
1 3 30
2 3 10
3

样例输出
40
#include <iostream>
#include <algorithm>
#include <algorithm>
#include <vector>
#include <queue>
#include <math.h>
using namespace std;

struct cmp {
    bool operator()(vector<int> &a, vector<int> &b) {
        return a[2] > b[2];  // 小顶堆
    }
};


class Solution {
public:
    vector<vector<vector<int>>> mat;
    vector<bool> visited;
    vector<int> dist;
    priority_queue<vector<int>, vector<vector<int>>, cmp> prq;
    int getAns(int n, int p) {
        mat.resize(n);
        visited.resize(n, false);
        dist.resize(n, INT_MAX);
        for (int i=0; i<p; ++i) {
            int src, dest, path;
            cin >> src >> dest >> path;
            mat[src].emplace_back(vector<int>{src, dest, path});
        }
        int finish;
        cin >> finish;
        return Dijkstra(0, finish);
    }
    int Dijkstra(int src, int dest) {
        int n = mat.size();
        visited[src] = true;
        dist[src] = 0;
        --n;
        for (auto &edge : mat[src])
            prq.push(edge);
        while (n) {
            vector<int> edge = prq.top();
            prq.pop();
            // 若连接对端节点已访问
            if (visited[edge[1]])
                continue;
            visited[edge[1]] = true;
            dist[edge[1]] = min(dist[edge[1]] , dist[edge[0]] +edge[2]);
            --n;
            for (auto &item : mat[edge[1]])
                prq.push(item);
        }
        return dist[dest];
    }
};


int main() {
    int n, p;
    cin >> n >> p;
    Solution *sol = new Solution();
    cout << sol->getAns(n, p) << endl;
}



//4 5
//0 1 15
//1 2 15
//0 3 50
//1 3 30
//2 3 10
//3
posted @ 2022-07-31 10:20  MasterBean  阅读(167)  评论(0)    收藏  举报