[NOIP 2018]旅行
题意简介:现有一个图,小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]旅行的更多相关文章
- NOIP 2018旅行题解
从佳木斯回来刷一刷去年没A的题 题目描述 小 Y 是一个爱好旅行的 OIer.她来到 X 国,打算将各个城市都玩一遍. 小Y了解到, X国的 nn 个城市之间有 mm 条双向道路.每条双向道路连接两个 ...
- noip 2018 d2t1 旅行
noip 2018 d2t1 旅行 (题目来自洛谷) 给定n个城市,m条双向道路的图, 不存在两条连接同一对城市的道路,也不存在一条连接一个城市和它本身的道路.并且, 从任意一个城市出发,通过这些道路 ...
- [OI]Noip 2018总结(普及)
考砸了,还有原谅我代码十分有限的可读性. 一个人的真正伟大之处就在于他能够认识到自己的渺小.——保罗 从一年前初一九月到现在18年10月接触OI已经有一年了.几次模拟赛也自我感觉良好,都过了一等的线, ...
- noip 2018 D1T3 赛道修建
noip 2018 D1T3 赛道修建 首先考虑二分答案,这时需要的就是对于一个长度求出能在树中选出来的最多的路径条数.考虑到一条路径是由一条向上的路径与一条向下的路径构成,或者仅仅是向上或向下的路径 ...
- NOIP 2018 总结
NOIP 2018 总结 提高组: 应得分 \(100 + 100 + 40 + 100 + 50 + 44 = 434\). 考后期望得分 \(100 + 100 + 20 + 100 + 50 + ...
- 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. ...
- NOIP 2018 普及组 解题报告
目录 标题统计 题目链接 思路 代码 龙虎斗 题目链接: 思路 代码 摆渡车 题目链接: 思路 对称二叉树 题目链接 思路: 先来解释一下为毛现在才来发解题报告: 其实博主是参加过NOIP 2018普 ...
- NOIp 2018 D2T1 旅行//未完成
这个题没有认真读的话就会写下以下的DD代码 #include<bits/stdc++.h> #define N 5010 using namespace std; int n,m; int ...
- noip 2018 Day2 T1 旅行
暴力删边,暴力枚举 #include <bits/stdc++.h> using namespace std; #define MAXM 5010 inline int read() { ...
随机推荐
- 剑指offer11:输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。(进制转换,补码反码)
1. 题目描述 输入一个整数,输出该数二进制表示中1的个数.其中负数用补码表示. 2. 思路和方法 使用移位(<<)和 “| & !”操作来实现.1的二进制是:前面都是0,最后一位 ...
- Python-21-socket编程
一.基础知识 1. C/S架构 C/S架构即客户机/服务器模式. 它可以分为客户机和服务器两层: 第一层: 在客户机系统上结合了界面显示与业务逻辑: 第二层: 通过网络结合了数据库服务器. 简单的 ...
- python学习-59 hashlib模块
hashlib模块 用于加密相关的操作,3.x里代替了md5模块和sha模块 加密功能 import hashlib obj = hashlib.md5() # 如果在md5里加上自己设置的参数,别的 ...
- 2019牛客暑期多校训练营(第四场)A meeting(dfs或dp,dp待更新)
示例1: 输入: 4 21 23 13 42 4 输出:2 说明: They can meet at place 1 or 3. 题意:从K个点到达不联通图某个点需要的最短时间,这个最短时间是这K个人 ...
- FFmpeg开发教程一、FFmpeg 版 Hello world
本系列根据项目ffmpeg-libav-tutorial翻译而来 Chapter 0 - 万物之源 -- hello world 然而,本节的程序并不会在终端打印"Hello world&q ...
- 解决windows 激活问题
解决windows 激活问题 下载 然后 搞定 重启
- Lucene入门+实现
Lucene简介详情见:(https://blog.csdn.net/Regan_Hoo/article/details/78802897) lucene实现原理 其实网上很多资料表明了,lucene ...
- 十分钟快速创建 Spring Cloud 项目
一般来说,Intelij IDEA 可以通过 Maven Archetype 来快速生成Maven项目,其实 IDEA 集成了 Spring 官方提供的 Spring Initializr,可以非常方 ...
- 3.asp.net core 关键概念
1. StartUp类 在Startup.ConfigureServices方法里配置或注册服务 在Startup.Configure方法里配置请求处理管道.请求处理管道由一系列中间件组建构成,每个中 ...
- hadoop入门-centos7.2安装hadoop2.8
1. 安装准备 (1)必须安装jdk: 因为hadoop是基于Java实现的,所有必须安装jdk 是JDK不是jre jdk1.7 jdk1.8 (2)系统位数 (3)创建专用用户 useradd h ...