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;
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

企事业单位宣传任务的考核稿和投稿有哪些网站?

企事业单位在宣传任务方面扮演着重要角色&#xff0c;他们不仅要向公众展示自己的实力和影响力&#xff0c;也需要提高自己的知名度和形象。在这个信息化时代&#xff0c;涌现出了许多网络平台&#xff0c;为企事业单位提供了更多的宣传机会。本文将介绍一家被广泛认可的投稿平…

模型Model:文件系统模型QFileSystemModel

一、 1、常用函数 QFileSystemModel自带目录变化监听 1)、 QModelIndex setRootPath(const QString &path); 设置检索根目录 2)、 bool isDir(const QModelIndex &index) const; 选中索引是否为目录节点 3)、 QString filePath(const QModelIndex &index) const;…

算法和数据结构--树状数组

概念&#xff1a; 树状数组的初衷是解决状态压缩空间里的累积频率&#xff0c;现在多用于求前缀和与后缀和(方便计算)&#xff0c;它可以以 O(logN)的时间得到任意前缀和&#xff0c;并同时支持在 O(logN)时间内支持动态单点值的修改。空间复杂度 O(N)。 树状数组的引用&#…

如何根据自己的数据集微调一个 Transformer 模型

将通过 NLP 中最常见的文本分类任务来学习如何在自己的数据集上利用迁移学习&#xff08;transfer learning&#xff09;微调一个预训练的 Transformer 模型—— DistilBERT。DistilBERT 是 BERT 的一个衍生版本&#xff0c;它的优点在它的性能与 BERT 相当&#xff0c;但是体积…

Unity3d C#实现场景编辑/运行模式下3D模型XYZ轴混合一键排序功能(含源码工程)

前言 在部分场景搭建中需要整齐摆放一些物品&#xff08;如仓库中的货堆、货架等&#xff09;&#xff0c;因为有交互的操作在单个模型上&#xff0c;每次总是手动拖动模型操作起来也是繁琐和劳累。 在这背景下&#xff0c;我编写了一个在运行或者编辑状态下都可以进行一键排序…

【嘉立创EDA-PCB设计指南】3.网络表概念解读+板框绘制

前言&#xff1a;本文对网络表概念解读板框绘制&#xff08;确定PCB板子轮廓&#xff09; 网络表概念解读 在本专栏的上一篇文章【嘉立创EDA-PCB设计指南】2&#xff0c;将设计的原理图转为了PCB&#xff0c;在PCB界面下出现了所有的封装&#xff0c;以及所有的飞线属性&…

从0开始python学习-48.pytest框架之断言

目录 1. 响应进行断言 1.1 在yaml用例中写入断言内容 1.2 封装断言方法 1.3 在执行流程中加入断言判断内容 2. 数据库数据断言 2.1 在yaml用例中写入断言内容 2.2 连接数据库并封装执行sql的方法 2.3 封装后校验方法是否可执行 2.4 使用之前封装的断言方法&#xff0c…

austin-admin 消息推送平台前端项目依赖低代码平台Amis 怎么使用

austin-admin 消息推送平台前端项目&#x1f525;依赖低代码平台Amis 怎么使用 收到一个通知&#xff0c;要将部署一个开源的消息系统 :austin的前端开源&#xff1a;https://gitee.com/zhongfucheng/austin-admin 本地运行 1、使用npm或者yarn这些咯 yarn yarn start2、使用…

【LabVIEW FPGA入门】FPGA中的数学运算

数值控件选板上的大部分数学函数都支持整数或定点数据类型&#xff0c;但是需要请注意&#xff0c;避免使用乘法、除法、倒数、平方根等函数&#xff0c;此类函数比较占用FPGA资源&#xff0c;且如果使用的是定点数据或单精度浮点数据仅适用于FPGA终端。 1.整数运算 支持的数…

pyechart基础

pyecharts - A Python Echarts Plotting Library built with love. 全局配置项 初识全局配置组件 Note: 配置项章节应该配合图表类型章节中的 example 阅读。 全局配置项可通过 set_global_opts 方法设置 InitOpts&#xff1a;初始化配置项 class pyecharts.options.InitO…

Java顺序表(2)

&#x1f435;本篇文章将对ArrayList类进行讲解 一、ArrayList类介绍 上篇文章我们对顺序表的增删查改等方法进行了模拟实现&#xff0c;实际上Java提供了ArrayList类&#xff0c;而在这个类中就包含了顺序表的一系列方法&#xff0c;这样在用顺序表解决问题时就不用每次都去实…

【C++干货铺】红黑树 (Red Black Tree)

个人主页点击直达&#xff1a;小白不是程序媛 C系列专栏&#xff1a;C干货铺 代码仓库&#xff1a;Gitee 目录 前言 红黑树的概念 红黑树的性质 红黑树结点的定义 红黑树的插入操作 插入新的结点 检查规则进行改色 情况一 情况二 情况三 插入完整代码 红黑树的验…

SpringMVC参数接收见解4

# 4.参数接收Springmvc中&#xff0c;接收页面提交的数据是通过方法形参来接收&#xff1a; 处理器适配器调用springmvc使用反射将前端提交的参数传递给controller方法的形参 springmvc接收的参数都是String类型&#xff0c;所以spirngmvc提供了很多converter&#xff08;转换…

【数据结构】归并排序的两种实现方式与计数排序

前言&#xff1a;在前面我们讲了各种常见的排序&#xff0c;今天我们就来对排序部分收个尾&#xff0c;再来对归并排序通过递归和非递归的方法进行实现&#xff0c;与对计数排序进行简单的学习。 &#x1f496; 博主CSDN主页:卫卫卫的个人主页 &#x1f49e; &#x1f449; 专栏…

Android Matrix绘制PaintDrawable设置BitmapShader,手指触点为圆心scale放大原图,Kotlin

Android Matrix绘制PaintDrawable设置BitmapShader&#xff0c;手指触点为圆心scale放大原图&#xff0c;Kotlin 在 Android基于Matrix绘制PaintDrawable设置BitmapShader&#xff0c;以手指触点为中心显示原图的圆切图&#xff0c;Kotlin&#xff08;4&#xff09;-CSDN博客 的…

2001-2022年上市公司企业财务绩效、公司价值、并购绩效数据(ROA、ROE、TOBINQ变化)

2001-2022年上市公司企业财务绩效、公司价值、并购绩效数据&#xff08;ROA、ROE、TOBINQ变化&#xff09; 1、时间&#xff1a;2001-2022年 2、指标&#xff1a;证券代码、统计截止日期、证券简称、行业代码、行业名称、年份、、总资产净利润率B、净资产收益率(ROE)B、托宾Q…

【方法】如何压缩zip格式文件?

zip是一种常见的压缩文件格式&#xff0c;能够高效打包文件便于存储和传输&#xff0c;那zip格式的压缩文件要如何压缩呢&#xff1f; 压缩zip文件需要用到解压缩软件&#xff0c;比如常见的WinRAR、7-Zip软件都可以压缩zip格式。下面一起来看看具体如何操作。 一、使用WinRAR…

日期处理第一篇--优雅好用的Java日期工具类Joda-Time

日常开发中&#xff0c;处理时间和日期是很常见的需求。基础的java内置工具类只有Date和Calendar&#xff0c;但是这些工具类的api使用并不是很方便和强大&#xff0c;于是就诞生了Joda-Time这个专门处理日期时间的库。 简介 Joda-Time提供了Java日期处理的优雅的替代品&…

IntelliJ IDEA 拉取gitlab项目

一、准备好Gitlab服务器及项目 http://192.168.31.104/root/com.saas.swaggerdemogit 二、打开 IntelliJ IDEA安装插件 打开GitLab上的项目&#xff0c;输入项目地址 http://192.168.31.104/root/com.saas.swaggerdemogit 弹出输入登录用户名密码&#xff0c;完成。 操作Comm…

【昕宝爸爸小模块】图文源码详解什么是线程池、线程池的底层到底是如何实现的

➡️博客首页 https://blog.csdn.net/Java_Yangxiaoyuan 欢迎优秀的你&#x1f44d;点赞、&#x1f5c2;️收藏、加❤️关注哦。 本文章CSDN首发&#xff0c;欢迎转载&#xff0c;要注明出处哦&#xff01; 先感谢优秀的你能认真的看完本文&…