【最短路--Yen(无重复K最短路) + Python】

1.前言

最近在学习《交通网络均衡理论》这门课,我计划将其中的一些经典算法用Python实现,而后发布到这里来和大家交流,欢迎指正。


2.代码实现

'''
@Author: Michael 2022-09-16 21:57:27
This code is about Yen.

'''

from Dijkstra import Dijkstra
import copy

def Short_limit(mgraph, inf, start, end, passed:list, noaccess:list):
    '''
    mgraph 为临界距离矩阵(以列表储存)
    inf    为设置的极大值
    passed 为当前必须经过点
    nopass 为当前禁止通行路段,以列表储存,其元素为二维列表,表示禁止通行的路段

    path   为当前条件下最短路径,以列表储存
    dis  为当前条件下最短路长度

    此处start,end,passed,noaccess均为现实标号

    '''

    mgraph_copy_1 = copy.deepcopy(mgraph)
    mgraph_copy_2 = copy.deepcopy(mgraph)

    if len(passed) != 0:
        start = passed[-1]

    for i,j in noaccess:
        mgraph_copy_2[i-1][j-1] = inf

    for i in passed:
        for j in range(len(mgraph)):
        #此步保证无重复点
            if i != passed[-1]:
                mgraph_copy_2[i-1][j] = inf
            mgraph_copy_2[j][i-1] = inf

    path,dis = Dijkstra(mgraph_copy_2,start,end,inf)

    path = passed[:-1]+path
    for k in range(len(passed)-1):
        dis += mgraph_copy_1[passed[k]-1][passed[k+1]-1]

    return path, dis

def Init(mgraph,inf,start,end,k):  #初始化
    passed, noaccess, path, dis = [],[],[],[]
    PASS,DIS = [],[]
    path_,dis_ = Short_limit(mgraph, inf, start, end, passed, noaccess)
    PASS.append(path_)
    DIS.append(dis_)
    k = k-1

    for i in range(len(path_)-1):
        passed.append(path_[:i+1])
        noaccess.append([[path_[i],path_[i+1]]])

    for i in range(len(passed)):
        path_,dis_ = Short_limit(mgraph,inf,start,end,passed[i],noaccess[i])
        path.append(path_)
        dis.append(dis_)
    return passed, noaccess, path, dis, PASS, DIS, k

def Branch(passed, noaccess, path, dis, k, PASS, DIS):
    inx = dis.index(min(dis))
    PASS.append(path[inx])
    DIS.append(dis[inx])
    k = k-1

    for i in range(len(passed[inx]),len(path[inx])):
        passed.append(passed[inx]+path[inx][len(passed[inx]):i])
        noaccess.append(noaccess[inx]+[path[inx][i-1:i+1]])
        path_,dis_ = Short_limit(mgraph, inf, start, end, passed[-1], noaccess[-1])
        # if path_ == passed[-1][:-1]:
        if dis_ >= 999:
            del passed[-1]
            del noaccess[-1]
        else:
            path.append(path_)
            dis.append(dis_)

    del passed[inx]
    del noaccess[inx]
    del path[inx]
    del dis[inx]

    while k>0 and len(path) != 0:
        Branch(passed, noaccess, path, dis, k, PASS, DIS)
        return PASS, DIS

def Yen(mgraph, inf, start, end, k):
    passed, noaccess, path, dis, PASS, DIS, k = Init(mgraph,inf,start,end,k)
    PASS, DIS = Branch(passed, noaccess, path, dis, k, PASS, DIS)
    print(f"共寻得{len(PASS)}最短路")
    for i in range(len(DIS)):
        print(f'第{i+1}短路,长{DIS[i]},{PASS[i]}')


测试

inf = 999 #此处表示极大值
mgraph = [[0,1,5,inf,inf,inf],
 [inf,0,3,1,6,inf],
 [6,2,0,4,2,inf],
 [inf,4,2,0,5,8],
 [inf,3,10,1,0,3],
 [inf,inf,inf,inf,inf,0]]
start,end,k = 1,6,15

Yen(mgraph, inf, start, end, k)

输出

共寻得15最短路
第1短路,9,[1, 2, 3, 5, 6]2短路,9,[1, 2, 4, 3, 5, 6]3短路,10,[1, 3, 5, 6]4短路,10,[1, 2, 5, 6]5短路,10,[1, 2, 4, 6]6短路,10,[1, 2, 4, 5, 6]7短路,15,[1, 2, 3, 5, 4, 6]8短路,16,[1, 2, 3, 4, 6]9短路,16,[1, 3, 2, 4, 6]10短路,16,[1, 3, 5, 4, 6]11短路,16,[1, 2, 5, 4, 6]12短路,16,[1, 2, 3, 4, 5, 6]13短路,16,[1, 3, 2, 5, 6]14短路,16,[1, 3, 2, 4, 5, 6]15短路,17,[1, 3, 4, 6]

3.优化方向

我的头快要裂开了,有没有懂得来帮看看,能不能把初始化函数Init()也整合到Branch()中,我这搞得好繁琐。
var code = “501d1c33-701a-4c89-9648-dee3a082bbd8”

4.参考资源

[1] 史峰.组合优化理论与计算方法.
[2]【最短路–Dijkstra + Python】

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
下面是使用 Yen算法求K短路的C++代码。其中,我们使用了Dijkstra算法作为最短路算法的实现。 ```c++ #include <iostream> #include <vector> #include <queue> #include <algorithm> #include <cstring> using namespace std; const int INF = 0x3f3f3f3f; const int MAXN = 100005; const int MAXM = 500005; struct Edge { int to, next, w; } edge[MAXM]; int head[MAXN], edgeNum; int dis[MAXN], vis[MAXN], pre[MAXN]; int n, m, k; void addEdge(int u, int v, int w) { edge[edgeNum].to = v; edge[edgeNum].w = w; edge[edgeNum].next = head[u]; head[u] = edgeNum++; } void dijkstra(int s) { priority_queue<pair<int, int>, vector<pair<int, int> >, greater<pair<int, int> > > pq; memset(dis, INF, sizeof(dis)); memset(vis, 0, sizeof(vis)); memset(pre, -1, sizeof(pre)); dis[s] = 0; pq.push(make_pair(dis[s], s)); while (!pq.empty()) { int u = pq.top().second; pq.pop(); if (vis[u]) continue; vis[u] = 1; for (int i = head[u]; i != -1; i = edge[i].next) { int v = edge[i].to; if (dis[v] > dis[u] + edge[i].w) { dis[v] = dis[u] + edge[i].w; pre[v] = u; pq.push(make_pair(dis[v], v)); } } } } vector<int> Astar(int s, int t, int k) { priority_queue<pair<int, int>, vector<pair<int, int> >, greater<pair<int, int> > > pq; vector<int> res; if (s == t) return res; pq.push(make_pair(0, s)); int cnt = 0; while (!pq.empty()) { cnt++; if (cnt > 1000000) break; int g = pq.top().first; int u = pq.top().second; pq.pop(); if (u == t) { res.push_back(g); if (res.size() == k) return res; } for (int i = head[u]; i != -1; i = edge[i].next) { int v = edge[i].to; if (v == pre[u]) continue; pq.push(make_pair(g + edge[i].w + dis[v] - dis[u], v)); } } return res; } void Yen(int s, int t, int K) { vector<vector<int> > paths(K, vector<int>()); vector<int> candidates; dijkstra(s); if (dis[t] == INF) return; candidates = Astar(s, t, 1); for (int k = 0; k < K && !candidates.empty(); k++) { int w = candidates.back(); candidates.pop_back(); paths[k].push_back(s); for (int i = t; i != -1; i = pre[i]) paths[k].push_back(i); reverse(paths[k].begin(), paths[k].end()); for (int i = 0; i < paths[k].size() - 1; i++) { int u = paths[k][i]; int v = paths[k][i + 1]; for (int j = head[u]; j != -1; j = edge[j].next) { if (edge[j].to == v && edge[j].w == w) { edge[j].w = INF; break; } } } dijkstra(s); candidates = Astar(s, t, 1); } for (int i = 0; i < K; i++) { if (paths[i].empty()) break; cout << "Path " << i + 1 << ": "; for (int j = 0; j < paths[i].size(); j++) cout << paths[i][j] << " "; cout << endl; } } int main() { memset(head, -1, sizeof(head)); cin >> n >> m >> k; for (int i = 0; i < m; i++) { int u, v, w; cin >> u >> v >> w; addEdge(u, v, w); } Yen(1, n, k); return 0; } ``` 其中,dijkstra()函数是使用堆优化的Dijkstra算法实现,Astar()函数是A*算法实现,Yen()函数是Yen算法的具体实现。在Yen()函数中,我们首先使用Dijkstra算法求出起点到终点的最短路径,并使用A*算法求出第一条最短路,然后对于每条路径,我们找出其路径上的边,并将其权值设为无穷大,再次使用Dijkstra算法求出起点到终点的最短路径,并使用A*算法求出新的最短路重复上述步骤,直到找到K条不同的最短路或者无法找到更多的可行路径为止。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值