每周一算法:最短路计数

devtools/2024/10/21 15:31:59/

题目描述

给出一个 N N N个顶点 M M M 条边的无向无权图,顶点编号为 1 1 1 N N N

问从顶点 1 1 1 开始,到其他每个点的最短路有几条。

输入格式

第一行包含 2 2 2 个正整数 N , M N,M N,M,为图的顶点数与边数。

接下来 M M M 行,每行两个正整数 x , y x,y x,y,表示有一条顶点 x x x 连向顶点 y y y 的边,请注意可能有自环与重边。

输出格式

输出 N N N 行,每行一个非负整数,第 i i i 行输出从顶点 1 1 1 到顶点 i i i 有多少条不同的最短路,由于答案有可能会很大,你只需要输出对 100003 100003 100003 取模后的结果即可。

如果无法到达顶点 i i i 则输出 0 0 0

样例 #1

样例输入 #1

5 7
1 2
1 3
2 4
3 4
2 3
4 5
4 5

样例输出 #1

1
1
1
2
4

提示

【数据范围】
1 ≤ N ≤ 1 0 5 1≤N≤10^5 1N105,
1 ≤ M ≤ 2 × 1 0 5 1≤M≤2×10^5 1M2×105

算法思想

根据题目描述,求从起点 1 1 1 到每个顶点有多少条不同的最短路,即求最短路的方案数。可以使用动态规划的思想,定义状态 f [ i ] f[i] f[i]表示起点到顶点 i i i的最短路的方案数。

要在图中计算状态,需要先构造出图的拓扑序列。但是题目中给出的是无向无权图,通过测试样例可以看出,图中有可能存在环,如下图所示,因此不一定存在拓扑序列,因此不能通过循环迭代直接计算状态。
在这里插入图片描述
由于求的是最短路的方案数,考虑能否使用最短路算法,在计算最短路的同时将状态计算出来。要使用最短路计算方案数需要要满足不能存在代价为 0 0 0的环,否则经过该环的最短路的方案数为无穷大。而题目中题目给出的是无向无权图,可以认为边权都为 1 1 1,因此不存在代价为 0 0 0的环。

那么有哪些最短路算法可以进行状态计算呢?

题目求的是起点到其余顶点的最短路,那么可以选择的最短路算法有:BFS、Dijkstra、Bellman-Ford(SPFA)等,是不是这些算法都可以用来计算状态呢?要计算 i i i点的状态,必须保证 i i i阶段所依赖的状态都已经被计算出来,也就是说在计算最短路时,能够找到一个拓扑序来计算状态。这样就需要最短路算法能够构造出一个最短路拓扑图。如下图所示:
在这里插入图片描述

而对于下列算法

  • BFS算法计算(边权相同的)最短路时,是一层一层进行扩展的,每个点只会入队 1 1 1次,出队 1 1 1次,进队和出队都是满足拓扑序的。
  • Dijkstra算法计算最短路时,每个点只会出队 1 1 1次,当一个点出队时,是不会更新前面已经出队的点到起点的最短路,因此出队序列也满足拓扑序。
  • Bellman-Ford(SPFA)算法计算最短路时,每个点可以入队出队多次,当一个点出队时可能会更新之前出队的点的最短路,这样就不能保证出队序列具备拓扑序。

也就是说, BFS和 Dijkstra算法在求最短路过程中可以进行状态计算。

算法流程

  • 将起点 1 1 1的最短路径方案数初始化为 1 1 1,即 f [ 1 ] = 1 f[1] = 1 f[1]=1
  • 在求解最短路的过程中
    • v v v点到起点的最短路能够被 u u u点松弛,即 d i s [ v ] > d i s [ u ] + 1 dis[v] > dis[u] + 1 dis[v]>dis[u]+1,则到 v v v的最短路方案数等于到 u u u点的最短路方案数,即 f [ v ] = f [ u ] f[v] = f[u] f[v]=f[u]
    • v v v点到起点的最短路等于经过 u u u点中转的距离,则需要累加到 u u u点的最短路方案数,即 f [ v ] = f [ v ] + f [ u ] f[v] =f[v] + f[u] f[v]=f[v]+f[u]

代码实现

#include <bits/stdc++.h>
//注意:边数为200000,无向图需要建双向边,所以边的总数为400010
const int N = 100010, M = 400010, mod = 100003;
int n, m;
int h[N], e[M], ne[M], idx;
//dist[i]表示从1号点到i号点的最短距离
//f[i]表示从1到点到i号点的最短距离的路径数
int dis[N], f[N], q[N];
void add(int a, int b)
{e[idx] = b, ne[idx] = h[a], h[a] = idx ++;
}
void bfs()
{memset(dis, 0x3f, sizeof dis);//注意,到1号点的最短路径数初始为1dis[1] = 0, f[1] = 1;//bfs每个点只会入队一次,使用普通队列即可int hh = 0, tt = 0;q[0] = 1;while(hh <= tt){int u = q[hh ++];for(int i = h[u]; ~i; i = ne[i]){int v = e[i];//可以更新最短距离if(dis[v] > dis[u] + 1){dis[v] = dis[u] + 1;q[++ tt] = v;//此时的路径数不变f[v] = f[u];}   else if(dis[v] == dis[u] + 1)//如果最短距离相等,累加最短路径数{f[v] = (f[v] + f[u]) % mod;}}}
}int main()
{scanf("%d%d", &n, &m);memset(h, -1, sizeof h);while(m --){int a, b;scanf("%d%d", &a, &b);add(a, b), add(b, a);  //无向图,双向边}bfs();for(int i = 1; i <= n; i++) printf("%d\n", f[i]);return 0;
}

http://www.ppmy.cn/devtools/16724.html

相关文章

MySQL 开源到商业(二):开源骇客沦为大厂社畜

前文提到&#xff0c;MySQL AB 接受了 Sun 公司的收购要约&#xff0c;开源骇客 Monty 也同时加入了 Sun 公司。双方对于 MySQL 的开源前景踌躇满志&#xff0c;准备大力投入新一代存储引擎 Maria 的开发&#xff0c;用于取代被 Oracle 收购的 InnoDB 引擎。作为一个芬兰人&…

基于Spring Boot的考研资讯平台设计与实现

基于Spring Boot的考研资讯平台设计与实现 开发语言&#xff1a;Java框架&#xff1a;springbootJDK版本&#xff1a;JDK1.8数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/idea 系统部分展示 系统功能界面图&#xff0c;在系统首页可以查看首页、考…

算法学习笔记——专题拓展5:并查集(Union-find)算法

介绍 并查集&#xff08;Union-Find&#xff09;算法是一个专门针对「动态连通性」的算法&#xff0c;同时它也是最小生成树算法的前置知识。 模板代码 class UF{private:int count;int* parent;public:UF(int n){this->count n;this->parent new int[n];for(int i …

Pytorch下张量的形状操作(详细)

目录 一、基本操作函数 二、分类&#xff1a;维度改变&#xff0c;张量变形&#xff0c;维度重排 2.1维度改变 2.2张量变形 2.3维度重排 三、实例 一、基本操作函数 在PyTorch中&#xff0c;对张量的形状进行操作是常见的需求&#xff0c;因为它允许我们重新组织、选择和…

金融级国产化替代中间件有哪些?

过去&#xff0c;国内中间件市场一直由IBM、Oracle等国际大型企业所主导&#xff0c;这在一定程度上限制了对国内企业多样化和个性化需求的满足&#xff0c;尤其是在实现底层硬件与上层应用软件之间高效、精准匹配方面。面对日益复杂的国际局势&#xff0c;金融安全已成为国家整…

Reactjs数据篇

参考代码&#xff1a;GitHub - leellun/zhiqu-web-test2 1 通过createAction创建Action做数据传递 在 Redux 中定义动作的常用方法是分别声明一个动作类型常量和一个动作创建器函数来构造该类型的动作。 store/action.ts import { createAction } from "reduxjs/toolk…

Python内存管理与垃圾回收机制深度解析

Python内存管理与垃圾回收机制深度解析 在Python编程中&#xff0c;内存管理是一项至关重要的任务。与其他一些编程语言不同&#xff0c;Python提供了自动内存管理功能&#xff0c;程序员无需显式地分配和释放内存。这一特性大大简化了编程过程&#xff0c;减少了内存泄漏等问…

发布自己的npm包

注册账号 首先需要先到npm官网注册个账号&#xff0c;https://www.npmjs.com 。 注意&#xff0c;邮箱需要认证&#xff0c;否则上传包的时候就会报错。 关联​ 接下来打开powershell(cmd等皆可)&#xff0c;关联npm账号&#xff0c; 按照提示依次输入注册的信息&#xff…