NOIP2018提高组day2 - T1:旅行

题目链接

[NOIP2018 提高组] 旅行

题目描述

小 Y 是一个爱好旅行的 OIer。她来到 X 国,打算将各个城市都玩一遍。

小 Y 了解到,X 国的 n n n 个城市之间有 m m m 条双向道路。每条双向道路连接两个城市。 不存在两条连接同一对城市的道路,也不存在一条连接一个城市和它本身的道路。并且, 从任意一个城市出发,通过这些道路都可以到达任意一个其他城市。小 Y 只能通过这些 道路从一个城市前往另一个城市。

小 Y 的旅行方案是这样的:任意选定一个城市作为起点,然后从起点开始,每次可 以选择一条与当前城市相连的道路,走向一个没有去过的城市,或者沿着第一次访问该 城市时经过的道路后退到上一个城市。当小 Y 回到起点时,她可以选择结束这次旅行或 继续旅行。需要注意的是,小 Y 要求在旅行方案中,每个城市都被访问到。

为了让自己的旅行更有意义,小 Y 决定在每到达一个新的城市(包括起点)时,将它的编号记录下来。她知道这样会形成一个长度为 n n n 的序列。她希望这个序列的字典序 最小,你能帮帮她吗? 对于两个长度均为 n n n 的序列 A A A B B B,当且仅当存在一个正整数 x x x,满足以下条件时, 我们说序列 A A A 的字典序小于 B B B

  • 对于任意正整数 1 ≤ i < x 1 ≤ i < x 1i<x,序列 A A A 的第 i i i 个元素 A i A_i Ai 和序列 B B B 的第 i i i 个元素 B i B_i Bi 相同。
  • 序列 A A A 的第 x x x 个元素的值小于序列 B B B 的第 x x x 个元素的值。

输入格式

输入文件共 m + 1 m + 1 m+1 行。第一行包含两个整数 n , m ( m ≤ n ) n,m(m ≤ n) n,m(mn),中间用一个空格分隔。

接下来 m 行,每行包含两个整数 u , v ( 1 ≤ u , v ≤ n ) u,v (1 ≤ u,v ≤ n) u,v(1u,vn) ,表示编号为 u u u v v v 的城市之 间有一条道路,两个整数之间用一个空格分隔。

输出格式

输出文件包含一行, n n n 个整数,表示字典序最小的序列。相邻两个整数之间用一个 空格分隔。

样例 #1

样例输入 #1

6 5 
1 3 
2 3 
2 5 
3 4 
4 6

样例输出 #1

1 3 2 5 4 6

样例 #2

样例输入 #2

6 6 
1 3 
2 3 
2 5 
3 4 
4 5 
4 6

样例输出 #2

1 3 2 4 5 6

提示

【数据规模与约定】

对于 100 % 100\% 100% 的数据和所有样例, 1 ≤ n ≤ 5000 1\le n \le 5000 1n5000 m = n − 1 m = n − 1 m=n1 m = n m = n m=n

对于不同的测试点, 我们约定数据的规模如下:

在这里插入图片描述

算法思想

根据题目描述:

  • 任意选定一个城市作为起点,然后从起点开始,每次可以选择一条与当前城市相连的道路,走向一个没有去过的城市,或者沿着第一次访问该 城市时经过的道路后退到上一个城市
  • 在旅行方案中,每个城市都被访问到

访问过程的就是一个DFS序列,要求的其中字典序最小的序列。

从数据范围来看,有 m = n − 1 m = n − 1 m=n1 m = n m = n m=n两种情况,由于从任意一个城市出发,通过这些道路都可以到达任意一个其他城市,也就是说:

  • m = n − 1 m = n − 1 m=n1 时,城市与道路构成一棵树
  • m = n m = n m=n时,就是在树上在加一条边,构成基环树,也叫环套树,是一种有 n n n个点 n n n条边的图。

树的深度优先遍历

先处理 m = n − 1 m = n - 1 m=n1的情况,即对一棵树进行DFS。为了得到字典序最小的DFS序列,就必须从 1 1 1号点开始遍历,每次按编号从小到大的顺序遍历所有子节点。

时间复杂度

DFS遍历树的时间复杂度为 O ( n + m ) O(n+m) O(n+m)

代码实现(60分)

#include <iostream>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
const int N = 5005;
vector<int> g[N];
vector<int> ans(N, N); //答案序列全部初始化为N
int cnt = 0;
bool st[N];
int n, m;
void dfs(int u)
{st[u] = 1;ans[cnt ++] = u;for(int v : g[u]) //遍历子结点{if(st[v]) continue;dfs(v);}
}
int main()
{scanf("%d%d", &n, &m);for(int i = 0; i < m; i ++){int a, b;scanf("%d%d", &a, &b);g[a].push_back(b), g[b].push_back(a); //连接a和b的双向边}//对每个节点的子节点按编号从小到大排序for(int i = 1; i <= n; i ++) sort(g[i].begin(), g[i].end());dfs(1);for(int i = 0; i < n; i ++) cout << ans[i] << " ";return 0;
}

基环树

在上述实现中,只会遍历 n n n个点和与其相邻的的 n − 1 n−1 n1条边。当 m = n m = n m=n时,就是在树上在加一条边,即树中有一个环,构成基环树。那是否要先把环找出来再处理呢?

从数据范围来看, 1 ≤ n ≤ 5000 1\le n \le 5000 1n5000 n n n比较小,可以枚举一条构成环的边,将其删除;然后DFS求出最小字典序即可。

在DFS过程中,通过维护当前序列和最优序列的大小关系可以进行最优性剪枝。如果当前序列的字典序一定大于最优序列,则直接退出。

时间复杂度

  • 枚举边的时间复杂度为 O ( m ) O(m) O(m)
  • DFS遍历树的时间复杂度为 O ( n + m ) O(n + m) O(n+m)

总的时间复杂度为 O ( n 2 ) O(n^2) O(n2)

代码实现(100分)

#include <iostream>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
typedef pair<int, int> PII;
const int N = 5005;
vector<int> g[N];
vector<int> ans(N, N); //答案序列,全部初始化为N
vector<int> cur(N); //存储当前搜索序列
int cnt, cmp; 
bool st[N];
int n, m, du, dv;
vector<PII> e;
void dfs(int u)
{if(cmp == 0) //当前序列和答案序列相等{if(u < ans[cnt]) cmp = -1; //当前序列字典序更小,继续搜索if(u > ans[cnt]) { cmp = 1; return ; } //当前序列字典序更大,剪枝}st[u] = 1; //标记已访问cur[cnt ++] = u; //存储访问的城市编号for(int v : g[u]) //遍历子结点{if(st[v] || (u == du && v == dv) || (u == dv && v == du)) continue;dfs(v);}
}
int main()
{scanf("%d%d", &n, &m);for(int i = 0; i < m; i ++){int a, b;scanf("%d%d", &a, &b);g[a].push_back(b), g[b].push_back(a); //连接a和b的双向边e.push_back({a, b}); //存边}//对每个节点的子节点按编号从小到大排序for(int i = 1; i <= n; i ++) sort(g[i].begin(), g[i].end());if(m == n - 1) {dfs(1);ans = cur;}else{for(int i = 0; i < m; i ++) //枚举要删除的边{du = e[i].first, dv = e[i].second;//cmp用来比较搜索序列和答案序列的字典序,初始为0表示相等cnt = cmp = 0;memset(st, 0, sizeof st);dfs(1);if(cnt == n && cmp < 0) //遍历完所有的点,并且搜索序列的字典序更小ans = cur;}}for(int i = 0; i < n; i ++) cout << ans[i] << " ";return 0;
}

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

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

相关文章

uniapp使用安装sass

1.首先你要安装node-sass npm install node-sass --save-dev2.安装sass-loader npm install sass-loader --save-dev3.修改style标签&#xff0c;声明使用sass <style lang"scss" scoped>

做完十年数据分析后的思考与总结

种一棵树最好的时间是十年前&#xff0c;其次是现在。十年了&#xff0c;本次分享大多来自工作中的日常所思所想&#xff0c;欢迎自取。 01 数据分析的本质 数据是基础&#xff0c;分析才是重点。 行业内有专门的统计岗&#xff0c;就是只负责做好数据统计就可以了&#xff0…

【Python】PyCharm设置控制台输出的行数限制

在使用PyCharm的时候&#xff0c;如果在控制台输出的信息过多室&#xff0c;控制台仅会保留一部分的输出信息。想要改变这个限制&#xff0c;设置方法如下&#xff1a; 进入到PyCharm的安装目录下&#xff0c;我的是C:\Develop\PyCharm202303\PyCharm 2023.3进入bin找到文件id…

sqlite | c++ | demo

sqlite 过得的废话 就不细说了 接下来&#xff0c;主要讲 安装sqlite 然后写一个demo &#xff0c;然后再shell 命令操作sqlite #安装 sqlite 程序 以及开发包 我的linux 环境是centos sudo yum install sqlite-3.7.17-8.el7_7.1.x86_64 sqlite-devel#输入 sqlite3 测试是否安装…

django后台登录:Forbidden (403) CSRF verification failed. Request aborted.

如果您在尝试登录Django后台时遇到了CSRF验证失败的错误&#xff0c;这通常意味着您的浏览器未能提交正确的CSRF令牌&#xff0c;或者Django后端未能验证该令牌。遵循以下步骤来解决这个问题&#xff1a; 清除浏览器Cookies和缓存&#xff1a; 有时候&#xff0c;浏览器的Cooki…

Linux systemd的概述与发展历程

systemd是一个系统和服务管理器&#xff0c;广泛用于现代Linux系统。它的设计目标是取代传统的SysVinit作为Linux系统的初始化系统&#xff0c;提供更快的启动速度、更好的并行性和更多的功能。本文将对systemd进行概述&#xff0c;并探讨其发展历程。 初始化系统 systemd负责…

C++:运算符重载

运算符重载的基本概念 与函数重载相似&#xff0c;运算符也存在重载问题。C为了解决一些实际问题&#xff0c;允许重载现有的大多数运算符&#xff0c;即允许给已有的运算符赋予新的含义&#xff0c;从而提高C的可扩展性&#xff0c;针对同样的操作&#xff0c;使用重载运算符…

【PostgreSQL】函数与操作符-位串函数和操作符

PostgreSQL函数与操作符-位串函数和操作符 PostgreSQL函数与操作符-位串函数和操作符描述用于检查和操作位串的函数和操作符&#xff0c;也就是操作类型为bit和bit varying的值的函数和操作符。除了常用的比较操作符之外&#xff0c;还可以使用下表里显示的操作符。&、|和…

ssh -T git@github.com Connection timed out 解决方案-自测有效

ssh -T gitgithub.com Connection timed out 解决方案-自测有效 $ ssh -T gitgithub.com $ ssh -vT gitgithub.com -p 443 OpenSSH_9.5p1, OpenSSL 3.1.4 24 Oct 2023 debug1: Reading configuration data /c/Users/Administrator/.ssh/config debug1: /c/Users/Administrator…

群晖NAS上安装部署开源工作流自动化工具n8n

一、开源工作流自动化工具n8n简介 n8n是它是一个与其他应用集成的应用程序&#xff0c;目标是自动化各应用之间的流程;利用 n8n 你可以方便地实现当 A 条件发生&#xff0c;触发 B 服务这样的自动工作流程。 n8n优点是&#xff1a;代码开源、可以自托管、下载安装方便、易于使用…

Java毕业设计第90期-基于springboot的学习英语管理系统

获取源码资料&#xff0c;请移步从戎源码网&#xff1a;从戎源码网_专业的计算机毕业设计网站 项目介绍 基于springboot的学习英语管理系统&#xff1a;前端 thymeleaf、jquery&#xff0c;后端 maven、springmvc、spring、mybatis&#xff0c;角色分为管理员、用户&#xff…

Java初学者软件安装与idea快捷键

一.Java初学者软件安装 视频教程&#xff1a; 最通俗易懂的JDK、IDEA的安装使用权威指南_哔哩哔哩_bilibili 文档教程&#xff1a; Java 开发环境配置 | 菜鸟教程 (runoob.com) 二.java的快捷方式与插件 快捷键&#xff1a; 史上最全的IDEA快捷键总结_idea的快捷语法_扬帆…

VSCode使用技巧

选择python 解释器 使用快捷键CtrlShiftP Python: Select Interpreter快捷键 返回上一次光标的位置 重新设置一下 navigate

【LLM】Prompt微调

Prompt 在机器学习中&#xff0c;Prompt通常指的是一种生成模型的输入方式。生成模型可以接收一个Prompt作为输入&#xff0c;并生成与该输入相对应的输出。Prompt可以是一段文本、一个问题或者一个片段&#xff0c;用于指导生成模型生成相应的响应、续写文本等。 Prompt优化…

springboot(ssm二手手机交易平台 二手机商城系统Java系统

springboot(ssm二手手机交易平台 二手机商城系统Java系统 开发语言&#xff1a;Java 框架&#xff1a;ssm/springboot vue JDK版本&#xff1a;JDK1.8&#xff08;或11&#xff09; 服务器&#xff1a;tomcat 数据库&#xff1a;mysql 5.7&#xff08;或8.0&#xff09; …

ROS第 2 课 ROS 系统安装和环境搭建

文章目录 方法一&#xff1a;一键安装&#xff08;推荐&#xff09;方法二&#xff1a;逐步安装&#xff08;常规安装方式&#xff09;1.版本选择2.检查 Ubuntu 的软件和更新源3.设置 ROS 的下载源3.1 设置国内下载源3.2 设置公匙3.3 更新软件包 4. 安装 ROS5. 设置环境变量6. …

JS -- 正则表达式教程

1 概念 ECMAScript 通过 RegExp 类型支持正则表达式。 2 写法 2.1 类似 Perl 的简写语法&#xff1a; let pattern /a/g let pattern2 /a/i2.2 构造函数创建&#xff1a; let pattern new RegExp(a, g) let pattern new RegExp(a, i)上面两种是等价的正则表达式 3 修…

Vue面试之Mixins

Vue面试之Mixins 定义Mixins使用Mixins全局MixinsMixins合并策略注意事项命名冲突&#xff1a;过度使用 最近在整理一些前端面试中经常被问到的问题&#xff0c;分为vue相关、react相关、js相关、react相关等等专题&#xff0c;可持续关注后续内容&#xff0c;会不断进行整理~ …

SpringBoot Redis入门(四)——Redis单机、哨兵、集群模式

单机模式&#xff1a;单台缓存服务器&#xff0c;开发、测试环境下使用&#xff1b;哨兵模式&#xff1a;主-从模式&#xff0c;提高缓存服务器的高可用和安全性。所有缓存的数据在每个节点上都一致。每个节点添加监听器&#xff0c;不断监听节点可用状态&#xff0c;一旦主节点…

ES6的一些冷门实用操作

ES6&#xff08;ECMAScript 2015&#xff09;引入了许多新的功能和语法&#xff0c;其中一些功能可能相对较冷门&#xff0c;但非常实用。本文将介绍一些这样的高级技巧&#xff0c;包括 Object.entries() Object.fromEntries() Array.of Array.from .at和flat WeakMap和W…