首页 > 其他分享 >浅析次短路

浅析次短路

时间:2022-12-14 20:35:19浏览次数:50  
标签:cnt dist nowd 短路 nowc int 浅析

统计次短路数量

Sightseeing

求最短路与次短路(只与最短路长度相差 \(1\) 的次短路)数量之和。

最短路

首先回顾我们如何统计最短路数量,我们使用 \(cnt[j]\) 表示从源点到 \(j\) 的最短路数量。

  1. dist[j] > dist[v] + w[i] 如果当前点 \(v\) 更新 \(dist[j]\) 的时候,发现从 \(v\) 出发是一个更优的选择,那么更新 \(cnt[j] = cnt[v]\);
  2. dist[j] == dist[v] + w[i] 如果当前点 \(v\) 更新 \(dist[j]\) 的时候,发现从 \(v\) 出发也是一条可行的最短路,那么更新 \(cnt[j] ++\);

想法

如果只有一个 \(dist[i]\) 数组不好表示次短路。

不妨运用 拆点的思想,将其扩展成二维的 \(dist[i][j](j\in \{0, 1\})\) 表示 :

  1. \(j = 0\) 时表示从源点到 \(i\) 的最短路的距离;
  2. \(j = 1\) 时表示从源点到 \(i\) 的次短路的距离。

同理,\(cnt[i][j](j\in \{0, 1\})\) 表示 :

  1. \(j = 0\) 时表示从源点到 \(i\) 的最短路的数量;
  2. \(j = 1\) 时表示从源点到 \(i\) 的次短路的数量。

思路

在想法的基础上,我们照葫芦画瓢地进行 \(cnt[i][j](j\in \{0, 1\})\) 的计算。

  1. \(dist[i][0] > nowd + w\),其中 \(nowd\) 表示当前点 \(dist[id][type]\) 的值,\(w\) 表示 \(i\) 到 \(j\) 的边权。即当前点出发时一个比目标点最短路更优的选择,那么从当前点出发的路径就自然地变成了目标点的新最短路,原来的最短路就变成了当前的次短路;
dist[j][1] = dist[j][0], cnt[j][1] = cnt[j][0]
dist[j][0] = nowd + w, cnt[j][0] = nowc // nowc 表示 cnt[id][type]
  1. \(dist[j][0] = nowd + w\) 即发现了一条新的可行的最短路,那么将其纳入彀中 cnt[j][0] += nowc

  2. \(dist[j][1] > nowd + w\) 即发现了一条更优的次短路,此时:

    • 如果比最短路优就更新最短路(实现的时候直接 else if 掉就没有这种情况了);
    • 如果没有最短路优,就只更新次短路即可 。
    dist[j][1] = nowd + w, cnt[j][1] = nowc
    
  3. \(dist[j][1] = nowd + w\) 即发现了一条新的可行的次短路,那么将其纳入彀中 cnt[j][0] += nowc

码来!

#include <iostream>
#include <algorithm>
#include <cstring>
#include <queue>
#include <iostream>

#define x first
#define y second

using namespace std;
typedef pair<int, int> PII;

struct qwq
{
    int x, type, y;
    bool operator> (const qwq& W) const
    {
        return y > W.y;
    }
};

int dist[N][3];
bool st[N][3];
int S, F;
vector<PII> g[N]; // vector存图方便快捷

int cnt[N][3];

void init(int n)
{
    for(int i = 1; i <= n; i ++) g[i].clear();
    memset(st, 0, sizeof st);
}

int dijkstra()  // 求1号点到n号点的最短路距离
{
    memset(dist, 0x3f, sizeof dist);
    cnt[S][0] = dist[S][0] = 1;
    priority_queue<qwq, vector<qwq>, greater<qwq>> q;
    q.push({S, 0, 0});

    while (q.size())
    {
        auto t = q.top();
        q.pop();

        int id = t.x;
        if (st[id][t.type]) continue;
        st[id][t.type] = true;

        for(auto i : g[id])
        {
            int j = i.x;
            int &nowd = dist[id][t.type];
            int &nowc = cnt[id][t.type];
            if(dist[j][0] > nowd + i.y)
            {
                dist[j][1] = dist[j][0], cnt[j][1] = cnt[j][0];
                dist[j][0] = nowd + i.y, cnt[j][0] = nowc;
                q.push({j, 1, dist[j][1]}); // 要记得把更新后的点丢进堆里
                q.push({j, 0, dist[j][0]});
            }
            else if(dist[j][0] == nowd + i.y)
                cnt[j][0] += nowc;
            else if(dist[j][1] > nowd + i.y)
            {
                dist[j][1] = nowd + i.y, cnt[j][1] = nowc;
                q.push({j, 1, dist[j][1]});
            }
            else if(dist[j][1] == nowd + i.y)
                cnt[j][1] += nowc;
        }
    }
    if(dist[F][0] == dist[F][1] - 1) return (cnt[F][0] + cnt[F][1]); // 判断次短路是否与最短路相差1,删掉这行就是次短路模板
    return cnt[F][0];
}

inline int read()
{
    int x = 0;
    char ch = getchar();
    while (ch < '0' || ch > '9')
        ch = getchar();
    while (ch <= '9' && ch >= '0')
        x = (x << 1) + (x << 3) + (ch ^ 48), ch = getchar();
    return x;
}

int main()
{
    int T;
    T = read();
    while(T --)
    {
        int n, m;
        n = read(), m = read();
        init(n);
        for(int i = 1; i <= m; i ++)
        {
            int a, b, c;
            a = read(), b = read(),  c = read();
            g[a].push_back({b, c});
        }
        S = read(), F = read();
        printf("%d\n", dijkstra());
    }
    return 0;
}

标签:cnt,dist,nowd,短路,nowc,int,浅析
From: https://www.cnblogs.com/MoyouSayuki/p/16983423.html

相关文章

  • 浅析BeanUtils中copyProperties原理
    摘要本文浅析BeanUtils中copyProperties的原理。简述大致实现流程源码浅析org.springframework.beans.BeanUtils/***将给定源bean的属性值赋值到目标bean中。*......
  • P5905 【模板】Johnson 全源最短路
    P5905【模板】Johnson全源最短路...处理负权边的方法十分巧妙,就像是势能一样算法上文链接有详解,就不赘述了,这样就实现了dij也可以处理负边是需要提前预处理一遍,建立......
  • JAVA Socket超时浅析
    转自:https://developer.aliyun.com/article/270260套接字或插座(socket)是一种软件形式的抽象,用于表达两台机器间一个连接的“终端”。针对一个特定的连接,每台机器上都有......
  • 同余最短路学习笔记
    感觉这个东西的构造好巧妙啊qwq那就写篇博客记一下吧qwqP3403跳楼机设\(d_i\)表示模\(x\)为\(i\)的能到达的最小楼层。那么\(i\xrightarrow{y}(i+y)\modx\)......
  • java中OOM错误浅析(没有深入太多,一些粗浅的知识,可以温习用)
    嗯,生活加油鸭。。。。实习中遇到OOM错误GCoverheadlimitexceeded  问题,所以整理一下OOM异常问题:不对的地方请小伙伴留言^_^“阿里的开发手册”对OOM的描述:OOM,全称“......
  • 浅析35kV变电站综合自动化系统的结构和功能设计
    罗轩志安科瑞电气股份有限公司上海嘉定201801 摘要:变电站综合自动化系统是一个分层分布式自动控制系统,整个系统由主控层、通信层和现地单元层三层构成。本文以35kV电站......
  • 浅析智能消防应急照明和疏散指示系统在工业建筑项目上的应用
    罗轩志安科瑞电气股份有限公司上海嘉定201801  摘要:随着我国社会经济的迅猛发展与城市化建设进程的加快,大型城市综合体建筑越来越多,随之而来的消防安全管理问题不容忽视......
  • 小程序开发入门及多端开发浅析
    前言现在小程序虽然不是最火的时间段,但是小程序“触手可及,用完即走”的理念对于未知开发者保持一定的神秘和吸引力,应后端同学对小程序开发的热情,笔者在疫情期间也开发上线了......
  • 《“透视”个人大数据》项目开发小记 --(三)Android APP 开发(3)使用jni调用c++/c 应用实
       目前应用AndroidStudio可以很方便的构建完成通过JNI调用c++/c的基本架构(CMakeLists,JNI调用C部分,java连接JNI部分)。希望通过APP开发中应用实例的简要介绍,可......
  • 最短路题型
    类型一.稍微变形的模板例:1.P1576最小花费松弛操作改了一点点。点击查看代码if(dis[v]>dis[u]/(1-0.01*w)){dis[v]=dis[u]/(1-0.01*w);q.push(make_pair(d......