[NOIP2018 TG D2T1]旅行
题目大意:$NOIP\;TG\;D2T1$
题解:一棵树的很简单,第一个点一定是$1$,只需要对每个节点,找最小的没有访问过的节点访问即可,我写的是$O(n\log_2n)$。
考虑基环树的部分,一个显然的想法是枚举一条环上的边,然后删掉,跑树的部分,复杂度为$O(mn\log_2n)$,明显过不了。于是考场上的我开始发扬人类智慧,发现有一个环上的边可以不经过,可以找这一条边的贡献,若不经过这条边的下一位和经过这条边的下一位进行比较,若不经过较优则不经过这条边。
出来问了一下,发现可以先把每个点的子树的儿子排序,再枚举删除的边可以做到$O(nm)$,可以过。
卡点:考试时写的代码可能会“多删除”几条边导致出错,并且仅当环上的点为当前的节点儿子中最大的节点时才会断这条边,而考场上没考虑到。考场上写了一个环的部分分,没有考虑到走回去的情况(如果不写,我的那个假的程序是可以跑对的,也就是说我白白丢了$12$分还花了时间,自闭了)
C++ Code:
#include <cstdio>
#include <algorithm>
#include <vector>
#define maxn 5010
inline int min(int a, int b) {return a < b ? a : b;} int head[maxn], cnt = 1;
struct Edge {
int to, nxt;
bool can;
} e[maxn << 1];
inline void add(int a, int b) {
e[++cnt] = (Edge) {b, head[a], true}; head[a] = cnt;
}
int n, m; namespace Work1 {
int ans[maxn], idx;
void dfs(int u, int fa = 0) {
ans[++idx] = u;
std::vector<int> V; V.clear();
for (int i = head[u]; i; i = e[i].nxt) {
int v = e[i].to;
if (v != fa) V.push_back(v);
}
std::sort(V.begin(), V.end());
for (std::vector<int>::iterator it = V.begin(); it != V.end(); it++) {
dfs(*it, u);
}
}
int main() {
for (int i = 1, a, b; i < n; i++) {
scanf("%d%d", &a, &b);
add(a, b);
add(b, a);
}
dfs(1);
for (int i = 1; i <= n; i++) {
printf("%d", ans[i]);
putchar(i == n ? '\n' : ' ');
}
return 0;
}
} namespace Work2 {
int C;
int ans[maxn], p[maxn], idx;
bool vis[maxn]; int res[maxn], scc;
int in_C = 0;
bool used_C = false; void dfs(int u, int fa = 0, int last = n + 1) {
vis[u] = true;
ans[++idx] = u;
std::vector<int> V; V.clear();
for (int i = head[u]; i; i = e[i].nxt) {
int v = e[i].to;
if (!vis[v] && v != fa) V.push_back(v);
}
std::sort(V.begin(), V.end());
for (std::vector<int>::iterator it = V.begin(); it != V.end(); it++) if (!vis[*it]) {
if (res[u] == res[*it]) {
if (in_C == u) used_C = true;
if (!in_C) in_C = u;
if (used_C) {
dfs(*it, u, n + 1);
} else {
if ((it + 1) == V.end()) {
if (*it < last) dfs(*it, u, last);
else used_C = true;
} else dfs(*it, u, *(it + 1));
}
} else dfs(*it, u, n + 1);
}
} int DFN[maxn], low[maxn];
int S[maxn], top;
void tarjan(int u, int father = 0) {
DFN[u] = low[u] = ++idx;
S[++top] = u;
int v;
for (int i = head[u]; i; i = e[i].nxt) if (i ^ father ^ 1) {
v = e[i].to;
if (!DFN[v]) {
tarjan(v, i);
low[u] = min(low[u], low[v]);
} else low[u] = min(low[u], DFN[v]);
}
if (DFN[u] == low[u]) {
scc++;
do {
v = S[top--];
res[v] = scc;
} while (v != u);
}
} inline bool check() {
for (int i = 1; i <= n; i++) if (ans[i] != p[i]) {
return p[i] < ans[i];
}
return false;
} void dfs2(int u, int fa = 0) {
p[++idx] = u;
std::vector<int> V; V.clear();
for (int i = head[u]; i; i = e[i].nxt) if (e[i].can) {
int v = e[i].to;
if (v != fa) V.push_back(v);
}
std::sort(V.begin(), V.end());
for (std::vector<int>::iterator it = V.begin(); it != V.end(); it++) {
dfs2(*it, u);
}
} int main() {
for (int i = 0, a, b; i < n; i++) {
scanf("%d%d", &a, &b);
add(a, b);
add(b, a);
}
tarjan(1);
for (int i = 1; i <= n; i++) ans[i] = n;
if (n < 500) {
for (int i = 2; i <= cnt; i += 2) {
int u = e[i ^ 1].to, v = e[i].to;
if (res[u] == res[v]) {
idx = 0;
e[i].can = e[i ^ 1].can = false;
dfs2(1);
if (check()) {
for (int j = 1; j <= n; j++) ans[j] = p[j];
}
e[i].can = e[i ^ 1].can = true;
}
}
for (int i = 1; i <= n; i++) {
printf("%d", ans[i]);
putchar(i == n ? '\n' : ' ');
}
return 0;
}
for (int i = 2; i <= cnt; i += 2) {
int u = e[i ^ 1].to, v = e[i].to;
if (res[u] == res[v]) {
C = res[u];
break;
}
}
idx = 0;
dfs(1);
for (int i = 1; i <= n; i++) {
printf("%d", ans[i]);
putchar(i == n ? '\n' : ' ');
}
return 0;
}
} int main() {
scanf("%d%d", &n, &m);
if (n - 1 == m) {
return Work1::main();
}
if (n == m) {
return Work2::main();
}
return 0;
}
[NOIP2018 TG D2T1]旅行的更多相关文章
- [NOIp2018提高组]旅行
[NOIp2018提高组]旅行: 题目大意: 一个\(n(n\le5000)\)个点,\(m(m\le n)\)条边的连通图.可以从任意一个点出发,前往任意一个相邻的未访问的结点,或沿着第一次来这个点 ...
- [NOIP2018 TG D2T2]填数游戏
题目大意:$NOIP2018\;TG\;D2T2$ 题解:在skip2004的博客基础上修改的,也是暴搜. 说明一下把vector改成数组并不可以通过此题,记录. 结论:在$m>n+1$时答案为 ...
- [NOIP2018 TG D1T3]赛道修建
题目大意:$NOIP2018\;TG\;D1T3$ 题解:题目要求最短的赛道的长度最大,可以想达到二分答案,接着就是一个显然的树形$DP$. 发现对于一个点,它子树中若有两条链接起来比要求的答案大,一 ...
- noip 2018 d2t1 旅行
noip 2018 d2t1 旅行 (题目来自洛谷) 给定n个城市,m条双向道路的图, 不存在两条连接同一对城市的道路,也不存在一条连接一个城市和它本身的道路.并且, 从任意一个城市出发,通过这些道路 ...
- @NOIP2018 - D2T1@ 旅行
目录 @题目描述@ @题解@ @代码@ @题目描述@ 小 Y 是一个爱好旅行的 OIer.她来到 X 国,打算将各个城市都玩一遍. 小Y了解到, X国的 n 个城市之间有 m 条双向道路.每条双向道路 ...
- NOIp 2018 D2T1 旅行//未完成
这个题没有认真读的话就会写下以下的DD代码 #include<bits/stdc++.h> #define N 5010 using namespace std; int n,m; int ...
- [NOIP2012 TG D2T1]同余方程
题目大意:求关于 x 的同余方程 ax ≡ 1 (mod b)的最小正整数解. 题解:即求a在mod b意义下的逆元,这里用扩展欧几里得来解决 C++ Code: #include<cstdio ...
- NOIp2018 TG day1 T2暨洛谷P5020 货币系统:题解
题目链接:https://www.luogu.org/problemnew/show/P5020 这道题感觉比较水啊,身为普及组蒟蒻都不费力的做出来了,而且数据范围应该还能大一些,n起码几万几十万都不 ...
- [NOIP2018 提高组] 旅行
考虑如果我们要回溯的话,一定要把非环上的子树都搜索完. 而在环上的一个地方回溯,相当于把环上的下一个点置于所有环的顺序的最后. 所以我们只有在环上遇到环上的最大点时且周围的点都比这个点小时非正常回溯即 ...
随机推荐
- java的动态验证码单线设计
1.java的动态验证码我这里将介绍两种方法: 一:根据java本身提供的一种验证码的写法,这种呢只限于大家了解就可以了,因为java自带的模式编写的在实际开发中是没有意义的,所以只供学习一下就可以了 ...
- Angular2入门学习
最近项目使用angular2,1和2版本变化大变样.下面总结一些学习网址及安装步骤. 中文官网(必看): https://angular.cn 懒人学习: http://www.imooc.com/l ...
- windows 下安装pyspider
今天主要介绍一下在Windows下安装pyspider,pyspider是一款用python编写的网络爬虫框架,这个框架最好是在linux下运行,Windows下运行可能会出现兼容性问题,如果实在要在 ...
- mysql帐号不允许从远程登陆
默认情况下,mysql帐号不允许从远程登陆,只能在localhost登录.本文提供了二种方法设置mysql可以通过远程主机进行连接. 一.改表法 在localhost登入mysql后,更改 “mysq ...
- 判断不同浏览器,加载不同的css和js文件
在低版本的IE中,条件注释还有效果,但是在ie9,10,11浏览器中,条件注释不起作用. 在网上找了个校验ie的方法. function isIE(){ if (window.ActiveXObje ...
- @Transactional spring 事务失效(转载)
原文地址:http://hwak.iteye.com/blog/1611970 1. 在需要事务管理的地方加@Transactional 注解.@Transactional 注解可以被应用于接口定义和 ...
- 教你Zbrush 4R7怎样创建Z球
随着CG行业的迅猛发展,就业门槛大幅度提高,对于从业人员要求就是要“又快又好”,作为一个模型师,常会碰到一天或两天完成一个全身角色的考题,而且还需要角度摆出造型,以前做这个的话,可能比较难,现在有了Z ...
- linux-clone-ip处理办法
vim /etc/udev/rules.d/70-persistent-net.rules 步骤1:#将eth0相关的文件给删除 步骤2:#vi /etc/sysconfig/network-scri ...
- Redis进阶:数据持久化,安全,在PHP中使用
一.redis数据持久化 由于redis是一个内存数据库,如果系统遇到致命问题需要关机或重启,内存中的数据就会丢失,这是生产环境所不能允许的.所以redis提供了数据持久化的能力. redis提供了两 ...
- swagger webapi控制器注释不显示
swagger是webapi文档描述及调试工具,要在asp.net mvc中使用swagger,需要安装Swashbuckle.Core这个包,安装好后会在app_start中生成SwaggerCon ...