题目链接

题意简介:现有一个图,小Y要把它走完,每个点只去一次,路径字典序最小。

分析:这道题我认为很重要的一个点就是它的数据范围。它只有两种 m=n-1 或 m=n。我们先考虑第一种:m=n-1也就是边为节点数减一,这种说法已经很隐晦了,其实这种情况就是树啊。树的遍历且字典序最小什么的应该很多人都会做吧,就只用深搜一下,这60分还是很好拿的。(由于每个点只做一次sort所以是不会超时的!)

void dfs_60(int u,int fa){
ans[++top]=u;
int ver[],k;
k=;
memset(ver,,sizeof(ver));
for(int i=head[u];i;i=next[i]){
if(to[i]!=fa)ver[++k]=to[i];
}
sort(ver+,ver+k+);
for(int i=;i<=k;++i){
dfs_60(ver[i],u);
}
return ;
}

然后我们要想个办法解决一个m=n的情况,并且在前面60的基础上加一些改动以达到ac的效果。那么m=n到底是个什么呢?他叫做:基环树。用我的理解来说,就是树里有一个环(也可以说是随便将一棵树上本不相连的两个点连接)。他大概长什么样子呢(m=n):

em,基本上是这个样子。其实啊,基环树这个东西,换句话说,只要删去环中的一条边也就变成了一棵树(多少颗不同的树取决于环的大小),那么我们可不可以删呢?在这道题当中是可以的。因为每一个点只去一次,就是说不存在从环上某个点走出去再沿着环返回这个点的这种情况,最多只走k-1条边(k为组成环的边数)。那么这道题我们从这k条边中每次取一条边出来删,按照m=n-1计算出最佳答案,最后所有的答案取最佳的就好。

那么目前只有一个问题:如何找环?

我是用的DFS,由于这道题只可能有一个环(因为m=n),所以就直接遍历,用一个栈存可能是环的点,遍历到已遍历的点的时候,就全部出栈直到那个点也弹出去。如果这个点所有子树搜完都没有找到环,那么把这个点出栈就行了。

void findh(int u,int fa){
if(flag==)return;
for(int i=head[u];i;i=next[i]){
if(to[i]!=fa){
if(vis[to[i]]){
while(to[i]!=st[top_st]){
h[++hsum]=st[top_st--];
}
h[++hsum]=to[i];
flag=;
}
else{
vis[to[i]]=;
st[++top_st]=to[i];
findh(to[i],u);
if(flag==)return;
top_st--;
vis[to[i]]=;
} }
}
}

接下来就任意删边用m=n-1弄就行了。注意一边搜索一边剪枝,不然会超时。

完整代码:

#include<iostream>
#include<cstdio>
#include<fstream>
#include<cmath>
#include<algorithm>
#include<cstring>
using namespace std;
int read(){
char ch;
int res=,f=;
ch=getchar();
while(ch<''||ch>''){
if(ch=='-')f=-;
ch=getchar();
}
while(ch>=''&&ch<=''){
res=res*+(ch-'');
ch=getchar();
}
return res*f;
}
const int MAXN=;
int n,m,tot;
int head[MAXN],next[MAXN],to[MAXN];
int ans[MAXN],top;
int sz,sy,st[MAXN],top_st,vis[MAXN];
int h[MAXN],hsum,flag;
int lans[MAXN],ltop,flag_dfs;
void add(int x,int y){
to[++tot]=y;
next[tot]=head[x];
head[x]=tot;
}
bool check(int u,int v){
if(u==sz&&v==sy)return ;
if(u==sy&&v==sz)return ;
return ;
}
void dfs_60(int u,int fa){
ans[++top]=u;
if(flag_dfs==&&ans[top]<lans[top])flag_dfs=-;
if(flag_dfs==&&ans[top]>lans[top])flag_dfs=;
if(flag_dfs==)return;
if(flag_dfs==-&&top==n){
for(int i=;i<=top;++i){
lans[i]=ans[i];
}
flag_dfs=;
return;
}
int ver[],k=;
//memset(ver,0,sizeof(ver));
for(int i=head[u];i;i=next[i])if(to[i]!=fa&&check(u,to[i]))ver[++k]=to[i];
sort(ver+,ver+k+);
for(int i=;i<=k;++i)dfs_60(ver[i],u);
return ;
}
void findh(int u,int fa){
if(flag==)return;
for(int i=head[u];i;i=next[i]){
if(to[i]!=fa){
if(vis[to[i]]){
while(to[i]!=st[top_st]){
h[++hsum]=st[top_st--];
}
h[++hsum]=to[i];
flag=;
}
else{
vis[to[i]]=;
st[++top_st]=to[i];
findh(to[i],u);
if(flag==)return;
top_st--;
vis[to[i]]=;
} }
}
}
int main(){
n=read();m=read();
for(int i=;i<=m;++i){
int u,v;
u=read();v=read();
add(u,v);add(v,u);
}
memset(lans,/,sizeof(lans));
if(n==m+){
dfs_60(,);
for(int i=;i<=top;++i){
printf("%d ",ans[i]);
}
}
else{
st[++top_st]=;
findh(,);
sz=h[],sy=h[hsum],top=;
dfs_60(,);
for(int i=;i<=hsum;++i){
sz=h[i-],sy=h[i],top=,flag_dfs=;
//memset(ans,0,sizeof(ans));
dfs_60(,);
}
}
for(int i=;i<=n;++i){
printf("%d ",lans[i]);
}
}
return ;
}

注:我注释掉了一些初始化的操作,是因为反正存答案的时候会覆盖,只用把top清零就行了

[NOIP 2018]旅行的更多相关文章

  1. NOIP 2018旅行题解

    从佳木斯回来刷一刷去年没A的题 题目描述 小 Y 是一个爱好旅行的 OIer.她来到 X 国,打算将各个城市都玩一遍. 小Y了解到, X国的 nn 个城市之间有 mm 条双向道路.每条双向道路连接两个 ...

  2. noip 2018 d2t1 旅行

    noip 2018 d2t1 旅行 (题目来自洛谷) 给定n个城市,m条双向道路的图, 不存在两条连接同一对城市的道路,也不存在一条连接一个城市和它本身的道路.并且, 从任意一个城市出发,通过这些道路 ...

  3. [OI]Noip 2018总结(普及)

    考砸了,还有原谅我代码十分有限的可读性. 一个人的真正伟大之处就在于他能够认识到自己的渺小.——保罗 从一年前初一九月到现在18年10月接触OI已经有一年了.几次模拟赛也自我感觉良好,都过了一等的线, ...

  4. noip 2018 D1T3 赛道修建

    noip 2018 D1T3 赛道修建 首先考虑二分答案,这时需要的就是对于一个长度求出能在树中选出来的最多的路径条数.考虑到一条路径是由一条向上的路径与一条向下的路径构成,或者仅仅是向上或向下的路径 ...

  5. NOIP 2018 总结

    NOIP 2018 总结 提高组: 应得分 \(100 + 100 + 40 + 100 + 50 + 44 = 434\). 考后期望得分 \(100 + 100 + 20 + 100 + 50 + ...

  6. NOIP 2018 真・退役记

    目录 NOIp 2018 真・退役记 7.01 7.05 \(summary\) 7.12 7.18 7.26 - 7.27 8.2 8.3 8.3 8.7 8.9 8.20 8.24 8.27 8. ...

  7. NOIP 2018 普及组 解题报告

    目录 标题统计 题目链接 思路 代码 龙虎斗 题目链接: 思路 代码 摆渡车 题目链接: 思路 对称二叉树 题目链接 思路: 先来解释一下为毛现在才来发解题报告: 其实博主是参加过NOIP 2018普 ...

  8. NOIp 2018 D2T1 旅行//未完成

    这个题没有认真读的话就会写下以下的DD代码 #include<bits/stdc++.h> #define N 5010 using namespace std; int n,m; int ...

  9. noip 2018 Day2 T1 旅行

    暴力删边,暴力枚举 #include <bits/stdc++.h> using namespace std; #define MAXM 5010 inline int read() { ...

随机推荐

  1. Linux基础-01-Linux基础命令

    1. Linux命令的格式 1) Linux命令的语法格式: 命令 [选项] [参数] 2) 命令格式中命令.选项.参数的具体含义 a) 命令:告诉Linux(UNIX)操作系统做(执行)什么. b) ...

  2. Maven安装和加速

    Maven安装和加速 下载带二进制源码包,解压 将bin设置为环境变量 加速器,修改conf文件夹下的settings.xml文件,添加如下镜像配置: <mirrors> <mirr ...

  3. javascript 之 扩展对象 jQuery.extend

    在JQuery的API手册中,extend方法挂载在JQuery 和 JQuery.fn两个不同的对象上,但在JQuery内部代码实现的是相同的,只是功能各不相同. 官方解释: jQuery.exte ...

  4. 本地计算机上的mysql服务启动停止后,某些服务在未由其他服务或程序使用时将自动停止

    C:\Windows\system32>cd C:\Program Files\mysql-8.0.18-winx64\bin\ C:\Program Files\mysql-8.0.18-wi ...

  5. VS.NET(C#)--1.5_VS菜单功能

    VS菜单功能 文件菜单 1.新建 2.添加 编辑菜单 1.快速查找  ctrl+F 2.快速替换   ctrl+H 3.在文件中查找ctrl+shift+F 4.在文件中替换ctrl+shift+H ...

  6. maven - 多模块构建

    使用idea创建maven项目 点击next输入GroupId和ArtifactId 点击next创建项目,新建项目结构如下 修改demo打包方式为pom 按层级拆分创建模块model,server, ...

  7. Python基本数据类型及实例详解

    Python 中的变量不需要声明.每个变量在使用前都必须赋值,变量赋值以后该变量才会被创建. 在 Python 中,变量就是变量,它没有类型,我们所说的"类型"是变量所指的内存中对 ...

  8. kvm第二章--虚拟机管理

  9. Django配置websocket请求接口

    1.settings.py INSTALLED_APPS = [ '...', 'channels', '...', ] ASGI_APPLICATION = 'server.routing.appl ...

  10. js的变量类型

    参考网址:https://www.cnblogs.com/focusxxxxy/p/6390536.html (讲的蛮好得,图文并茂,我下面只是总结下) 一:ECMAScirpt 变量的两种数据类型 ...