学习笔记-最短路

1. 正权无向图最小环问题(floyd)引用链接:点我 抛开Dijkstra算法,进而我们想到用Floyd算法。我们知道,Floyd算法在进行时会不断更新矩阵dist(k)。设dist[k,i,j]表示从结点i到结点j且满足所有中间结点,它们均属于集合{1,2,⋯ ,k}的一条最短路径的权。其中dist[0,i,j ]即为初始状态i到j的直接距离。对于一个给定的赋权有向图, 求出其中...
摘要由CSDN通过智能技术生成

觉得讲的不详细可以去B站看:https://www.bilibili.com/video/av85550343

1. 正权无向图最小环问题(floyd)

引用链接:点我


    抛开Dijkstra算法,进而我们想到用Floyd算法。我们知道,Floyd算法在进行时会不断更新矩阵dist(k)。设dist[k,i,j]表示从结点i到结点j且满足所有中间结点,它们均属于集合{1,2,⋯ ,k}的一条最短路径的权。其中dist[0,i,j ]即为初始状态i到j的直接距离。对于一个给定的赋权有向图, 求出其中权值和最小的一个环。我们可以将任意一个环化成如下形式:u->k->v ->(x1-> x2-> ⋯ xm1)-> u(u与k、k与v都是直接相连的),其中v ->(x1-> 2-> ⋯ m)-> u是指v到u不经过k的一种路径。

    在u,k,v确定的情况下,要使环权值最小, 则要求 (x1一>x2->⋯一>xm)->u路径权值最小.即要求其为v到u不经过k的最短路径,则这个经过u,k,v的环的最短路径就是:[v到u不包含k的最短距离]+dist[O,u,k]+dist[O,k,v]。我们用Floyd只能求出任意2点间满足中间结点均属于集合{1,2,⋯ ,k}的最短路径,可是我们如何求出v到u不包含k的最短距离呢?
    现在我们给k加一个限制条件:k为当前环中的序号最大的节点(简称最大点)。因为k是最大点,所以当前环中没有任何一个点≥k,即所有点都<k。因为v->(x1->x2->......xm)->u属于当前环,所以x1,x2,⋯ ,xm<k,即x1,x2.⋯。xm≤k一1。这样,v到u的最短距离就可以表示成dist[k一1 ,u,v]。dist[k一1,v,u]表示的是从v到u且满足所有中间结点均属于集合{1,2,⋯ ,k一1}的一条最短路径的权。接下来,我们就可以求出v到u不包含k的最短距离了。这里只是要求不包含k,而上述方法用的是dist[k一1,v,u],求出的路径永远不会包含k+l,k+2,⋯ 。万一所求的最小环中包含k+1,k+2,⋯ 怎么办呢?的确,如果最小环中包含比k大的节点,在当前u,k,v所求出的环显然不是那个最小环。然而我们知道,这个最小环中必定有一个最大点kO,也就是说,虽然当前k没有求出我们所需要的最小环,但是当我们从k做到kO的时候,这个环上的所有点都小于kO了.也就是说在k=kO时一定能求出这个最小环。我们用一个实例来说明:假设最小环为1—3—4—5—6—2—1。的确,在u=l,v=4,k=3时,k<6,dist[3,4,1]的确求出的不是4—5—6—2—1这个环,但是,当u=4,v=6,k=5或u=5,v=2,k=6时,dist[k,v,u]表示的都是这条最短路径.所以我们在Floyd以后,只要枚举u.v,k三个变量即可求出最小环。时间复杂度为O(n3)。我们可以发现,Floyd和最后枚举u,v,k三个变量求最小环的过程都是u,v,k三个变量,所以我们可以将其合并。这样,我们在k变量变化的同时,也就是进行Floyd算法的同时,寻找最大点为k的最小环。


讲的听清楚的。

下面是我的板子(例题HDU1599):

#include <bits/stdc++.h>
using namespace std;
#define IO ios::sync_with_stdio(false);cin.tie(0)
#define forn(i, n) for(int i = 0; i < n; ++i)

const int inf = 2e7;

int dis[105][105], a[105][105];

int main() {
    IO;
    int n, m;
    while(cin >> n >> m) {
        forn(i, 105) forn(j, 105) dis[i][j] = a[i][j] = inf;
        forn(i, m) {
            int u, v, w;
            cin >> u >> v >> w;
            dis[u][v] = min(w, dis[u][v]);
            a[u][v] = a[v][u] = dis[v][u] = dis[u][v];
        }
        int ans = inf;
        for(int k = 1; k <= n; ++k) {
            for(int i = 1; i < k; ++i) {
                for(int j = i + 1; j < k; ++j) {
                    ans = min(ans, dis[i][j] + a[i][k] + a[k][j]);
                }
            }
            for(int i = 1; i <= n; ++i) {
                for(int j = 1; j <= n; ++j) {
                    dis[i][
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值