[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() { ...
随机推荐
- Java 发送http GET/POST请求
最近项目里面需要用到Java发送http请求,由于发送https请求有点复杂,暂时不考虑 HttpURLConnection HttpURLConnection是一种多用途.轻量极的HTTP客户端,使 ...
- C++语言类之间的关系
在c++中通过类定义对象,而类与类之间也有着复杂的关系,所以题外话,我能理解到c++的编写者可能就想通过计算机语言去模拟世界万物之间的关系,这篇帖子主要从横向和纵向去讨论类之间关系 而在一个类中想要使 ...
- Spring Boot使用@Value注解获取配置文件中的属性
获取配置文件的内容——
- dfs的剪枝优化
两个剪枝问题 1. 当两点的距离(需要走的步数)大于剩下的时间时 剪去 2.奇偶剪枝问题 如果起点到终点所需走的步数的奇偶性与时间奇偶性不同的时候 剪去 起点到终点步数的奇偶性的判断 首先 明确点的奇 ...
- java 线程并发(生产者、消费者模式)
线程并发协作(生产者/消费者模式) 多线程环境下,我们经常需要多个线程的并发和协作.这个时候,就需要了解一个重要的多线程并发协作模型“生产者/消费者模式”. Ø 什么是生产者? 生产者指的是负责生产数 ...
- java常见排序算法
今天去面试的时候又考了排序算法,排序这个东西,你以为你懂了,但是真正去写的时候才会发现好多细节自己都模棱两可,我写着写着就全都乱了,回来之后赶紧重新写一遍. (1)冒泡排序 public void b ...
- 拦截器中获取不到controller注解问题
刚刚在测试接口的时候发现一个奇怪的问题:通过拦截器获取 controller 类注解,有些能获取到,有些又不能获取到,见鬼了. [环境]: 1. springboot :2.2.0.RELEASE [ ...
- python—各种常用函数及库
列表list1.append(x) 将x添加到列表末尾 list1.sort() 对列表元素排序 list1.reverse() 将 ...
- windows上安装python虚拟环境
一.windows上安装python虚拟环境 1.安装pip install virtualenvvirtualenv --version 2.新建一个python虚拟环境virtual_env_01 ...
- Linux如何监控每个进程所消耗流量
查看整个系统的网卡流量使用情况 可以参考下这篇总结比较全面的文章 监控具体的某个进程所消耗的流程 首先,Linux没有自带这样的工具,通过这款第三方开源工具,也是比较好用,如果有其他的办法欢迎留言 # ...