AcWing 344 观光之旅

2024-03-08 08:59
文章标签 acwing 之旅 观光 344

本文主要是介绍AcWing 344 观光之旅,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

题目描述:

给定一张无向图,求图中一个至少包含3个点的环,环上的节点不重复,并且环上的边的长度之和最小。

该问题称为无向图的最小环问题。

你需要输出最小环的方案,若最小环不唯一,输出任意一个均可。

输入格式

第一行包含两个整数N和M,表示无向图有N个点,M条边。

接下来M行,每行包含三个整数u,v,l,表示点u和点v之间有一条边,边长为l。

输出格式

输出占一行,包含最小环的所有节点(按顺序输出),如果不存在则输出’No solution.’。

数据范围

1≤N≤100,
1≤M≤10000,
1≤l<500

输入样例:

5 7
1 4 1
1 3 300
3 1 10
1 2 16
2 3 100
2 5 15
5 3 20

输出样例:

1 3 5 2

分析:

本题考察floyd算法求最小环,并且要求输出最小环中所有的节点。

如图所示,设环上编号最大的节点编号是k,i和j分别是环上与k相邻的两个节点。根据之前对floyd算法的推导,f[k][i][j]表示图上i经过编号不超过k的节点到达j的最短路径长度,观察上图可以发现,环的长度等于i到j的最短距离加上g[i][k]再加上g[k][j],设环的长度为ans,则ans = f[i][j] + g[i][k] + g[k][j],这里的f[i][j]是对f[k-1][i][j]降维后的结果,为什么是f[k-1][i][j]而不是f[k][i][j],因为前面已经规定k是最大的节点,环上其他的节点必然都小于k。为什么要这么规定,这种思路是如何来的?后面会分析这种思路的由来。

我们知道,floyd算法最外层k刚刚循环到第k次时,f[i][j]存储的还是i经过编号不超过k-1的节点到达j的最短路径长度,此时的f[i][j]正是我们所需要的,因此在第k次循环开始时,由k,i,j加上i到j中间的节点构成的最小环长度就是f[i][j] + g[i][k] + g[k][j],我们还是用三层循环去枚举所有的情况,最终就可以求出最小环的长度。

for(int k = 1;k <= n;k++){for(int i = 1;i < k;i++){for(int j = i + 1;j < k;j++){if((ll)f[i][j] + g[i][k] + g[k][j] < ans){ans = f[i][j] + g[i][k] + g[k][j];cnt = 0;path[cnt++] = k,path[cnt++] = i;get_path(i,j);path[cnt++] = j;}}}for(int i = 1;i <= n;i++){for(int j = 1;j <= n;j++){if(f[i][k] + f[k][j] < f[i][j]){f[i][j] = f[i][k] + f[k][j];pos[i][j] = k;}}}}

上面是求最小环的核心代码,暂且不去看用来求环上所有节点的get_path的部分, 如果直接按照前面分析的思路去求解,想到的肯定是第一层循环k从1到n,第二三层是i,j从1到n,然后最内层先更新下最小环长度,在用floyd算法更新f[i][j]。而看到上面的代码肯定会有疑问,为什么要将最内层的两个循环分开写?问题的答案是为了提高效率,这背后的原因值得深思。如果一开始我们就按照floyd算法的习惯去进行状态表示,用f[k][i][j]表示以相邻的三点i,j,k以及i与j之间编号不超过k的节点构成的最小环长,也就是说,仅要求i到j中间的节点小于k,i,j与k的大小关系不明确规定,自然就可以按照floyd的写法三层循环都从1循环到n。这样写一方面需要判断i、j不能等于k,否则会违反环上至少三个点的规定;另一方面效率较低,我们直接选k作为环上最大的节点,图中任意一个环总有最大编号的节点,这是毫无疑问的,并且环上与k相邻的两点必然都小于k并且互不相等,这就保证了这种状态定义和实现对各种环状态转移的没有遗漏了。另一个问题是floyd算法能否也写成这样呢?第二三层循环的上限都设置为k-1,如果这样实现,floyd算法的状态表示就需要修改为f[k][i][j]表示从i到j包含i,j在内所有点编号都不超过k的最小路径长度,这样表示显然是不合理的,比如从任何点到n的最小距离我们就无法找到一个比n更大的中间点来作为k更新距离。

再来看记录最小环上节点的代码,在循环中,我们知道环上已经有i,j,k三点,只需要再存储下i到j的最短路径上节点的编号即可,如果i到j的最短路径经过了中间点k,那么i到j最短路径上的节点就被分为了三部分:i到k,k,k到j。问题的规模就缩小了,这就意味着可以递归的求解最短路径上的节点。还有个容易忽略的点就是每次最小环长被更新时都需要计算下此时环上有哪些节点,而不能仅仅是记录下此时的i,j,k,在算法结束后再计算,其中的原因求i到j最短路径上节点时用到了i到j的中间节点k,我们用pos[i][j]=k存储了此时最小环中i到j的中间节点k,但是随着k的递增,pos[i][j]的值也会不停地改变,等到算法结束时的pos[i][j]早已经不是最小环时候的k了。总的代码如下:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N = 105,INF = 0x3f3f3f3f;
int g[N][N],f[N][N],pos[N][N],path[N];
int m,n,cnt = 0;
void get_path(int i,int j){if(!pos[i][j])  return;get_path(i,pos[i][j]);path[cnt++] = pos[i][j];get_path(pos[i][j],j);
}
int main(){scanf("%d%d",&n,&m);int a,b,c;memset(g,0x3f,sizeof g);for(int i = 1;i <= n;i++)   g[i][i] = 0;for(int i = 0;i < m;i++){scanf("%d%d%d",&a,&b,&c);g[a][b] = g[b][a] = min(g[a][b],c);//防重边}memcpy(f,g,sizeof g);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++){if((ll)f[i][j] + g[i][k] + g[k][j] < ans){//防溢出ans = f[i][j] + g[i][k] + g[k][j];cnt = 0;path[cnt++] = k,path[cnt++] = i;get_path(i,j);path[cnt++] = j;}}}for(int i = 1;i <= n;i++){for(int j = 1;j <= n;j++){if(f[i][k] + f[k][j] < f[i][j]){f[i][j] = f[i][k] + f[k][j];pos[i][j] = k;}}}}if(ans == INF)  puts("No solution.");else{for(int i = 0;i < cnt;i++){printf("%d ",path[i]);}puts("");}return 0;
}

 

这篇关于AcWing 344 观光之旅的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/786610

相关文章

【AcWing】851. 求最短路

spfa算法其实是对贝尔曼福特算法做一个优化。 贝尔曼福特算法会遍历所有边来更新,但是每一次迭代的话我不一定每条边都会更新,SPFA是对这个做优化。 如果说dist[b]在当前这次迭代想变小的话,那么一定是dist[a]变小了,只有a变小了,a的后继(b)才会变小。 用宽搜来做优化,用一个队列,队列里边存的就是所有变小了的结点(队列里存的是待更新的点)。 基本思路就是我更新过谁,我再拿

Spring Boot 注解探秘:HTTP 请求的魅力之旅

在SpringBoot应用开发中,处理Http请求是一项基础且重要的任务。Spring Boot通过提供一系列丰富的注解极大地简化了这一过程,使得定义请求处理器和路由变得更加直观与便捷。这些注解不仅帮助开发者清晰地定义不同类型的HTTP请求如何被处理,同时也提升了代码的可读性和维护性。 一、@RequestMapping @RequestMapping用于将特定的HTTP请求映射到特定的方法上

【AcWing】852. spfa判断负环

#include<iostream>#include<algorithm>#include<cstring>#include<queue>using namespace std;const int N= 1e5+10;int n,m;int h[N],w[N],e[N],ne[N],idx;int dist[N],cnt[N];//cnt存最短路径的边数bool st[N];v

28.8K Star,音乐新体验,开启你的高颜值音乐之旅

Hi,骚年,我是大 G,公众号「GitHub 指北」会推荐 GitHub 上有趣有用的项目,一分钟 get 一个优秀的开源项目,挖掘开源的价值,欢迎关注。 导语 音乐是生活中不可或缺的调味品,一个好的音乐播放器能够极大地提升我们的听觉享受。今天,我要向大家推荐一个名为 YesPlayMusic 的第三方网易云音乐播放器,它不仅拥有高颜值的界面设计,还支持跨平台使用,让你的音乐体验更上一层楼

杨bob的技术之旅

杨bob今天正式入驻csdn,以后要把自己每一点滴写成文章,这也是冲高阶的毕竟之路

Midjourney 随机风格 (Style Random),开启奇幻视觉之旅

作者:老余捞鱼 原创不易,转载请标明出处及原作者。 写在前面的话:       Midjourney 最近推出了 "Style Random"(随机风格),这项功能可以让我们使用独特的随机 sref 代码创建图像,从而每次都能获得不同的美感。通过对这些功能的探索和尝试,我发现了一些很棒的风格,我很高兴能与大家分享,这样可以节省大家的时间,不用自己动手测试。在本文中,我将展示十个M

《长得太长也是错?——后端 Long 型 ID 精度丢失的“奇妙”修复之旅》

引言 在前后端分离的时代,我们的生活充满了无数的机遇与挑战——包括那些突然冒出来的让人抓狂的 Bug。今天我们要聊的,就是一个让无数开发者哭笑不得的经典问题:后端 Long 类型 ID 过长导致前端精度丢失。说到这个问题,那可真是“万恶之源”啊,谁让 JavaScript 只能安全地处理 Number.MAX_SAFE_INTEGER(也就是 9007199254740991)以内的数值呢?

SpringBoot与Minio的极速之旅:解锁文件切片上传新境界

目录 一、前言 二、对象存储(Object Storage)介绍 (1)对象存储的特点 (2)Minio 与对象存储 (3)对象存储其他存储方式的区别 (4)对象存储的应用场景 三、Minio基础介绍 (1)主要特性 (2)应用场景 (3)架构和部署 四、SringBoot集成MinIO实现切片上传 1. 引入依赖 2.配置MinIO相关配置信息 3. 配置 Min

微信公众号《GIS 数据工程:开始您的 ETL 之旅 》 文章删除及原因

微信公众号多次限制付费文章发布,不太明确其原因。我猜可能是得罪了某位大神,这倒是也不是不可能。我这说话口无遮拦,得罪几个人偶尔搞我一下也是应该的 。当然也可能是部分喜欢白嫖的网友一看我收费就不太高兴,偶尔做点小动作也是有可能的。还有就是平台可能有其它我未知的情况。反正也不猜了,这类问题纠结起来太浪费时间,所以认怂是最好的处理方式。 因此我只能改为线下购买。如有需要线下与我联系。以后

网关桥梁:modbus 转 profinet 网关中频加热机的智能融合之旅

一、项目序章:金属热处理的智慧曙光在金属锻造的辉煌舞台上,中频感应加热电源以其高效节能、精准控温的卓越才艺,成为了热处理、焊接与成型艺术中不可或缺的幕后英雄。然而,随着工业自动化的浪潮汹涌而至,如何让这位英雄融入智能工厂的广阔天地,实现远程指挥与智能操控,成为了新时代的命题。本案例,便是一场关于中频感应加热电源与工业网关携手,共绘智能工厂新蓝图的壮丽篇章。 二、系统蓝图:织就智慧互联的经纬1