题目大意:$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]旅行的更多相关文章

  1. [NOIp2018提高组]旅行

    [NOIp2018提高组]旅行: 题目大意: 一个\(n(n\le5000)\)个点,\(m(m\le n)\)条边的连通图.可以从任意一个点出发,前往任意一个相邻的未访问的结点,或沿着第一次来这个点 ...

  2. [NOIP2018 TG D2T2]填数游戏

    题目大意:$NOIP2018\;TG\;D2T2$ 题解:在skip2004的博客基础上修改的,也是暴搜. 说明一下把vector改成数组并不可以通过此题,记录. 结论:在$m>n+1$时答案为 ...

  3. [NOIP2018 TG D1T3]赛道修建

    题目大意:$NOIP2018\;TG\;D1T3$ 题解:题目要求最短的赛道的长度最大,可以想达到二分答案,接着就是一个显然的树形$DP$. 发现对于一个点,它子树中若有两条链接起来比要求的答案大,一 ...

  4. noip 2018 d2t1 旅行

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

  5. @NOIP2018 - D2T1@ 旅行

    目录 @题目描述@ @题解@ @代码@ @题目描述@ 小 Y 是一个爱好旅行的 OIer.她来到 X 国,打算将各个城市都玩一遍. 小Y了解到, X国的 n 个城市之间有 m 条双向道路.每条双向道路 ...

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

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

  7. [NOIP2012 TG D2T1]同余方程

    题目大意:求关于 x 的同余方程 ax ≡ 1 (mod b)的最小正整数解. 题解:即求a在mod b意义下的逆元,这里用扩展欧几里得来解决 C++ Code: #include<cstdio ...

  8. NOIp2018 TG day1 T2暨洛谷P5020 货币系统:题解

    题目链接:https://www.luogu.org/problemnew/show/P5020 这道题感觉比较水啊,身为普及组蒟蒻都不费力的做出来了,而且数据范围应该还能大一些,n起码几万几十万都不 ...

  9. [NOIP2018 提高组] 旅行

    考虑如果我们要回溯的话,一定要把非环上的子树都搜索完. 而在环上的一个地方回溯,相当于把环上的下一个点置于所有环的顺序的最后. 所以我们只有在环上遇到环上的最大点时且周围的点都比这个点小时非正常回溯即 ...

随机推荐

  1. Makefile中wildcard的介绍

    在Makefile规则中,通配符会被自动展开.但在变量的定义和函数引用时,通配符将失效.这种情况下如果需要通配符有效,就需要使用函数“wildcard”,它的用法是:$(wildcard PATTER ...

  2. c语言中 *p++ 和 (*p)++ 和 *(p++) 和 *(++p) 和++(*p)和 *(p--)和 *(--p)有什么区别?

    *p++是指下一个地址; (*p)++是指将*p所指的数据的值加一; /******************解释**********************/ ->C编译器认为*和++是同优先级 ...

  3. [Cracking the Coding Interview] 4.2 Minimal Tree 最小树

    Given a sorted(increasing order) array with unique integer elements, write an algorithm to create a ...

  4. Java——自动生成30道四则运算---18.09.27

    package chuti;import java.io.PrintWriter;import java.util.Scanner;import java.io.FileNotFoundExcepti ...

  5. python2.7入门---异常处理

        python提供了两个非常重要的功能来处理python程序在运行中出现的异常和错误.我们可以使用该功能来调试python程序. 异常处理. 断言(Assertions).     首先来看py ...

  6. JAVA大作业汇总3

    JAVA大作业3 代码 ``` package thegreatwork; import java.util.; import java.io.; /Board.java 目的:里面有一些关于如何移动 ...

  7. 设计模式——模版方法模式详解(论沉迷LOL对学生的危害)

    .  实例介绍 在本例中,我们使用一个常见的场景,我们每个人都上了很多年学,中学大学硕士,有的人天生就是个天才,中学毕业就会微积分,因此得了诺贝尔数学奖:也有的人在大学里学了很多东西,过得很充实很满意 ...

  8. python中判断输入是否为数字(包括浮点数)

    1.当num确定为数字后 num=123.4print(isinstance(num,float))#判断是否为浮点数 print(isinstance(num,int))#判断是否为整数 2.当nu ...

  9. springmvc常用jar包

    <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans ...

  10. js解决img标签加载失败显示默认图片

    问题: 为所有显示楼盘的页面添加一个加载失败的默认图片. 基本思路: img标签中有个onerror属性,专门用来处理加载失败的事件.所以可以用jquery添加onerror属性,在onerror中加 ...