C/C++、Python——迪杰斯特拉(Dijkstra)和弗洛伊德(Floyd)算法求最短路径及途经结点

效果

图

1. C++
int main() {
	vector<tuple<unsigned, unsigned, double>> es{ // 起点, 终点, 权重
        {0, 3, 1},
        {0, 4, 9},
        {0, 6, 1},
        {1, 3, 5},
        {1, 5, 3},
        {1, 6, 2},
        {2, 5, 4},
        {2, 6, 2},
        {3, 4, 7},
        {4, 5, 15} };
    Dijkstra path(7, es, 4); //7个顶点, 边集, 起点为4, 无向图
    Floyd pathf(7, es); //7个顶点, 边集,无向图
    cout << "Dijkstra: " << endl;
    for (unsigned i = 0; i < 7; ++i) {
        auto tp = path(i); // 起点到结点i的<最短路径值, 途径结点>
        cout << "weight: " << get<0>(tp) << ", path: " << get<1>(tp) << endl;
    } 
    cout << "Floyd: " << endl;
    for (unsigned i = 0; i < 7; ++i) {
        auto tp = pathf(i, 4); // 结点i到结点j的<最短路径值, 途径结点>
        cout << "weight: " << get<0>(tp) << ", path: " << get<1>(tp) << endl;
    }
}

在这里插入图片描述

2. Python
es = [(0, 3, 1),
      (0, 4, 9),
      (0, 6, 1),
      (1, 3, 5),
      (1, 5, 3),
      (1, 6, 2),
      (2, 5, 4),
      (2, 6, 2),
      (3, 4, 7),
      (4, 5, 15)]
pathf = Floyd(7, es)
for i in range(7):
    for j in range(i + 1, 7):
        path = Dijkstra(7, es, i)
        print('floyd: weight: {}, path: {}'.format(*pathf(i, j)))
        print('dijkstra: weight: {}, path: {}'.format(*path(j)))

在这里插入图片描述

代码:C++

#include <vector>
#include <string>
#include <tuple>
using namespace std;


string join(string s, vector<unsigned> list) { // 拼接向量元素为字符串
    if (list.empty()) return "";
    string res(to_string(list[0]));
    for (auto i = list.begin() + 1; i != list.end(); ++i) {
        res += s;
        res += to_string(*i);
    }
    return res;
}


class Dijkstra {
private:
    unsigned n; // 结点数
    unsigned start;
    vector<tuple<unsigned, unsigned, double>> edges; // 边集
    bool undirected; // 是否无向
    vector<double> dis; // 最短路径表
    vector<unsigned> pre; // 最短路径前驱结点
    void dijkstra() { // Dijkstra算法具体实现
        vector<vector<double>> mat(n, vector<double>(n, DBL_MAX));
        for (unsigned i = 0; i < n; ++i) mat[i][i] = 0;
        for (auto edge : edges) { // 生成邻接矩阵
            auto i = get<0>(edge), j = get<1>(edge);
            auto w = get<2>(edge);
            if (i == start) dis[j] = w;
            mat[i][j] = w;
            if (undirected) {
                mat[j][i] = w;
                if (j == start) dis[i] = w;
            }
        }
        vector<unsigned> done{ start }; // 已定结点集
        vector<unsigned> pending; // 待定结点集
        for (unsigned i = 0; i < n; ++i)
            if (i != start)
                pending.push_back(i);
        while (!pending.empty()) {
            auto relay_iter = pending.begin();
            for (auto point_iter = pending.begin() + 1; point_iter != pending.end(); ++point_iter)
                if (dis[*point_iter] < dis[*relay_iter]) // 取最近结点为中继
                    relay_iter = point_iter;
            auto relay = *relay_iter;
            done.push_back(relay);
            pending.erase(relay_iter);
            for (auto point : pending) // 以中继点更新待定结点
                if (dis[point] > dis[relay] + mat[relay][point]) {
                    dis[point] = dis[relay] + mat[relay][point];
                    pre[point] = relay;
                }
        }
    }
public:
    Dijkstra( // 构造:结点数、边集、起点、是否无向
        unsigned n,
        const vector<tuple<unsigned, unsigned, double>>& edges,
        unsigned start,
        bool undirected = true)
        :n(n), start(start), edges(edges), undirected(undirected),
        dis(vector<double>(n, DBL_MAX)), pre(vector<unsigned>(n, start)) {
        dijkstra();
    }
    tuple<unsigned, string> operator()(unsigned j) { // 重载()获取起点到结点j的路径
		if (start == j) return { 0, to_string(start) };
		if (dis[j] == DBL_MAX) return { DBL_MAX, "" };
		vector<unsigned> p{ j };
		while (pre[p.back()] != start) p.push_back(pre[p.back()]);
		p.push_back(start);
        reverse(p.begin(), p.end());
		return { dis[j], join("->", p) };
    }
};


class Floyd {
private:
    unsigned n; // 结点数
    vector<vector<double>> mat; // 邻接矩阵
    vector<vector<unsigned>> pre; // 前驱结点表
    void floyd() { // Floyd算法具体实现
        for (unsigned k = 0; k < n; ++k) // 依次作为中继结点
            for (unsigned i = 0; i < n; ++i)
                for (unsigned j = 0; j < n; ++j)
                    if (mat[i][j] > mat[i][k] + mat[k][j]) { // 以中继更新其他点
                        mat[i][j] = mat[i][k] + mat[k][j];
                        pre[i][j] = k;
                    }
    }
public:
    Floyd( // 构造:结点数,边集,是否无向
        unsigned n,
        vector<tuple<unsigned, unsigned, double>> edges,
        bool undirected = true) 
        :n(n), mat(vector<vector<double>>(n, vector<double>(n, DBL_MAX))) {
        for (unsigned i = 0; i < n; ++i) { // 生成邻接矩阵和前驱表
            mat[i][i] = 0;
            pre.push_back(vector<unsigned>(n, i));
        }
        for (auto edge : edges) {
            auto i = get<0>(edge), j = get<1>(edge);
            auto w = get<2>(edge);
            mat[i][j] = w;
            if (undirected) mat[j][i] = w;
        }
        floyd();
    }
    tuple<unsigned, string> operator()(unsigned i, unsigned j) { // 重载()获取结点i到结点j的路径
        if (i == j) return { 0, to_string(i) };
        if (mat[i][j] == DBL_MAX) return { DBL_MAX, "" };
        vector<unsigned> p{ i, j };
        unsigned k = 0;
        while (k < p.size() - 1) {
            auto iter = p.begin() + k;
            if (pre[*iter][*(iter + 1)] == *iter) ++k;
            else p.insert(iter + 1, pre[*iter][*(iter + 1)]);
        }
        return { mat[i][j], join("->", p) };
    }
};

代码:Python

class Dijkstra:
    def __init__(self, n, edges, start, undirected=True):
        self.n = n
        self.start = start
        self.edges = edges
        self.undirected = undirected
        self.dis = [float('inf')] * n
        self.pre = [start] * n
        self.dijkstra()

    def dijkstra(self):
        mat = [[float('inf')] * self.n for _ in range(self.n)]
        for i in range(self.n):
            mat[i][i] = 0
        for i, j, w in self.edges:
            if i == self.start:
                self.dis[j] = w
            mat[i][j] = w
            if self.undirected:
                mat[j][i] = w
                if j == self.start:
                    self.dis[i] = w
        done = [self.start]
        pending = [i for i in range(self.n) if i != self.start]
        while pending:
            relay = pending[0]
            for point in pending:
                if self.dis[point] < self.dis[relay]:
                    relay = point
            done.append(relay)
            pending.remove(relay)
            for point in pending:
                if self.dis[point] > self.dis[relay] + mat[relay][point]:
                    self.dis[point] = self.dis[relay] + mat[relay][point]
                    self.pre[point] = relay

    def __call__(self, j):
        if self.start == j:
            return 0, str(self.start)
        p = [j]
        while self.pre[p[-1]] != self.start:
            p.append(self.pre[p[-1]])
        p.append(self.start)
        return self.dis[j], '->'.join(str(c) for c in reversed(p)) if self.dis[j] != float('inf') else ''


class Floyd:
    def __init__(self, n, edges, undirected=True):
        self.n = n
        self.mat = [[float('inf')] * n for _ in range(n)]
        for i in range(n):
            self.mat[i][i] = 0
        for i, j, w in edges:
            self.mat[i][j] = w
            if undirected:
                self.mat[j][i] = w
        self.pre = [[r] * n for r in range(n)]
        self.floyd()

    def floyd(self):
        for k in range(self.n):
            for i in range(self.n):
                for j in range(self.n):
                    if self.mat[i][j] > self.mat[i][k] + self.mat[k][j]:
                        self.mat[i][j] = self.mat[i][k] + self.mat[k][j]
                        self.pre[i][j] = k

    def __call__(self, i, j):
        if i == j:
            return 0, str(i)
        p = [i, j]
        k = 0
        while k < len(p) - 1:
            if self.pre[p[k]][p[k + 1]] == p[k]:
                k += 1
            else:
                p.insert(k + 1, self.pre[p[k]][p[k + 1]])
        return self.mat[i][j], '->'.join(str(c) for c in p) if self.mat[i][j] != float('inf') else ''

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值