每周一算法:恰好经过K条边的最短路

题目描述

牛站

给定一张由 M M M 条边构成的无向图,点的编号为 1 ∼ 1000 1\sim 1000 11000 之间的整数。

求从起点 S S S 到终点 E E E 恰好经过 K K K 条边(可以重复经过)的最短路。

注意: 数据保证一定有解。

输入格式

1 1 1 行:包含四个整数 K , M , S , E K,M,S,E KMSE

2.. M + 1 2..M+1 2..M+1 行:每行包含三个整数,描述一条边的边长以及构成边的两个点的编号。

输出格式

输出一个整数,表示最短路的长度。

样例 #1

样例输入 #1

2 6 6 4
11 4 6
4 4 8
8 4 9
6 6 8
2 6 9
3 8 9

样例输出 #1

10

提示

【数据范围】
2 ≤ M ≤ 100 2≤M≤100 2M100,
2 ≤ K ≤ 1 0 6 2≤K≤10^6 2K106

算法思想

倍增 + Floyd 求状态

根据题目描述,求从起点 S S S到终点 E E E恰好经过 K K K条边的最短路。考虑「Floyd」算法中的状态 d [ K , i , j ] d[K,i,j] d[K,i,j]表示经过编号 1 ∼ K 1\sim K 1K的点进行中转、从顶点 i i i j j j的最短距离。本题可以用类似的状态 d [ K , i , j ] d[K,i,j] d[K,i,j]表示为恰好经过 K K K条边,从顶点 i i i j j j的最短距离。

要计算状态 d [ K , i , j ] d[K,i,j] d[K,i,j],很容易想到 d [ K , i , j ] = m i n { d [ K − 1 , i , k ] + g [ k , j ] } d[K,i,j]=min\{d[K-1, i, k]+g[ k, j]\} d[K,i,j]=min{d[K1,i,k]+g[k,j]},枚举一个中转点 k k k,从 K − 1 K-1 K1阶段的状态转移到 K K K。这样做的时间复杂度为 K × n 3 K\times n^3 K×n3,从数据范围来看, 2 ≤ M ≤ 100 , 2 ≤ K ≤ 1 0 6 2≤M≤100,2≤K≤10^6 2M1002K106,显然会TLE。

进一步分析,不妨假设 K = a + b K=a+b K=a+b,那么 d [ K , i , j ] = m i n { d [ a , i , k ] + d [ b , k , j ] } d[K,i,j]=min\{d[a,i,k]+d[b,k,j]\} d[K,i,j]=min{d[a,i,k]+d[b,k,j]},其中 k k k表示从 i i i出发经过恰好 a a a条边到达的顶点, 1 ≤ k ≤ n 1\le k\le n 1kn,如下图所示:
在这里插入图片描述
可以发现从顶点 i i i走到 k k k,和从顶点 k k k走到 j j j,这两个部分是完全独立的,并不相互依赖,所以先求前面、或者先求后面没有任何区别。也就是说,对于路径的组合可以是任意的,结合在一起答案不变,类似于加法结合律。

基于上述分析,可以使用快速幂“倍增”的思想,依次计算出 d [ 1 , i , j ] → d [ 2 , i , j ] → d [ 4 , i , j ] → . . . d[1,i,j]\to d[2,i,j]\to d[4,i,j]\to... d[1,i,j]d[2,i,j]d[4,i,j]...,可以将时间复杂度优化为 O ( l o g K × n 3 ) O(logK\times n^3) O(logK×n3)

离散化点集

除此之外,从给出的数据范围来看,边数 M ≤ 200 M\le200 M200 200 200 200条边最多连接 400 400 400个点,那么就需要对所有点进行离散化,重新编号为 1 ∼ n 1\sim n 1n

代码实现

#include <bits/stdc++.h>
using namespace std;
const int N = 205;
int g[N][N], d[N][N];
int n, m, K, S, E;
map<int, int> idx; //离散化点集
void mul(int c[][N], int a[][N], int b[][N])
{static int temp[N][N];memset(temp, 0x3f, sizeof temp);for(int k = 1; k <= n; k ++)for(int i = 1; i <= n; i ++)for(int j = 1; j <= n; j ++)temp[i][j] = min(temp[i][j], a[i][k] + b[k][j]);memcpy(c, temp, sizeof temp);
}
void qmi()
{//初始话状态数组memset(d, 0x3f, sizeof d);for(int i = 1; i <= n; i ++) d[i][i] = 0;while(K){if(K & 1) mul(d, d, g); // d = d * gmul(g, g, g); //g = g * gK >>= 1;}
}
int main()
{cin >> K >> m >> S >> E;memset(g, 0x3f, sizeof g); //初始化邻接矩阵//离散化起点和终点,重新分配编号idx[S] = ++ n; idx[E] = ++ n; S = idx[S], E = idx[E];for(int i = 0; i < m; i ++){int a, b, c;cin >> c >> a >> b; //注意输入顺序//将点离散化,重新分配编号if(!idx.count(a)) idx[a] = ++ n;if(!idx.count(b)) idx[b] = ++ n;a = idx[a], b = idx[b]; g[a][b] = g[b][a] = min(g[a][b], c);}qmi(); //快速幂,倍增求状态cout << d[S][E] << endl;return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/704779.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

万字长文破解 AI 图片生成算法-Stable diffusion (第一篇)

想象一下&#xff1a;你闭上眼睛&#xff0c;脑海中构思一个场景&#xff0c;用简短的语言描述出来&#xff0c;然后“啪”的一声&#xff0c;一张栩栩如生的图片就出现在你眼前。这不再是科幻小说里才有的情节&#xff0c;而是Stable Diffusion——一种前沿的AI图片生成算法—…

「AIGC」Python实现tokens算法

本文主要介绍通过python实现tokens统计,避免重复调用openai等官方api,开源节流。 一、设计思路 初始化tokenizer使用tokenizer将文本转换为tokens计算token的数量二、业务场景 2.1 首次加载依赖 2.2 执行业务逻辑 三、核心代码 from transformers import AutoTokenizer imp…

半小时搞懂STM32知识点——UART

1.UART 1.1为什么要使用UART这种协议?介绍一下UART及其特点 成本低&#xff0c;硬件简单&#xff0c;数据格式灵活&#xff1b; 低速全双工异步串行通信 1.2 UART数据帧格式&#xff1f; 起始位&#xff08;1&#xff09;&#xff0b;数据位&#xff08;5-8&#xff09; 校验位…

C语言详解:数组指针

数组指针是指针 int* p[10] 这是指针数组的写法 &#xff0c;因为【】的优先级比*高&#xff0c; 所以为了解决优先级问题&#xff0c;加&#xff08;&#xff09; int(* p)[10]&arr;//数组的地址要存起来 说明p是指针&#xff08;首先与*结合&#xff09;&#xff0c…

走进开源,拥抱开源

走进开源&#xff0c;拥抱开源 一、开源文化1.1 什么是开源1.2 为什么要开源1.3 有哪些开源协议 二、选择开源2.1 开源社区的类型与特点2.2 如何选择开源社区2.3 如何选择开源项目 三、参与开源3.1 开源社区的参与方式3.2 开源项目的参与方式 四、Apache Doris 参与示例4.1 Dor…

几个排序器的verilog及其资源占用、延时分析

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 前言 因为课题需要&#xff0c;调研了几个快速排序方法&#xff0c;并手写或者改进了若干待测试对象&#xff0c;包括记分板型冒泡排序&#xff08;这个是别人的&#xff09…

1、sql server数据库进行sql注入

靶机取自&#xff1a;墨者sql server 1、判断数据库类型 抓包知sql server&#xff0c;所以注入语句跟MySQL有些区别 2、判断注入点 “http://219.153.49.228:42514/new_list.asp?id2 ”&#xff0c;当id2 and 11时显示正确&#xff0c;id2 and 12时页面报错。 3、确定列…

基于单片机的智能安防系统设计(32+4G+WIFI版)-设计说明书

设计摘要&#xff1a; 本设计基于STM32单片机&#xff0c;旨在实现一个智能安防系统&#xff0c;主要包括烟雾和温度传感器、人体红外传感器、显示屏、按键、4G模块和WiFi模块等组件。通过这些组件的协作&#xff0c;实现了火灾检测、入侵监测、状态显示、用户交互和远程通信等…

软件工程期末复习(8)需求的表达方法和状态转换图

需求的表达方法 系统模型 需求分析的任务就是借助于当前系统的逻辑模型导出目标系统的逻辑模型&#xff0c;解决目标系统 “做什么” 的问题 通常软件开发项目是要实现目标系统的物理模型。目标系统的具体物理模型是由它的逻辑模型经实例化&#xff0c;即具体到某个业务领域而…

pytest教程-47-钩子函数-pytest_sessionfinish

领取资料&#xff0c;咨询答疑&#xff0c;请➕wei: June__Go 上一小节我们学习了pytest_sessionstart钩子函数的使用方法&#xff0c;本小节我们讲解一下pytest_sessionfinish钩子函数的使用方法。 pytest_sessionfinish 钩子函数在 Pytest 测试会话结束时调用&#xff0c;…

Java入门基础学习笔记23——For循环结构

1、for循环&#xff1a; 控制一段代码反复执行很多次。 2、For循环语句的基本结构&#xff1a; for(初始化表达式&#xff1b;判断表达式&#xff1b;递增&#xff08;递减&#xff09;表达式&#xff09; {循环体语句&#xff08;重复执行的代码&#xff09; } 例&#xff1…