[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 提高组] 旅行
考虑如果我们要回溯的话,一定要把非环上的子树都搜索完. 而在环上的一个地方回溯,相当于把环上的下一个点置于所有环的顺序的最后. 所以我们只有在环上遇到环上的最大点时且周围的点都比这个点小时非正常回溯即 ...
随机推荐
- xpath技术解析xm文件(php)
1.结合php dom技术的学习,得出一个结论:php dom技术可以跨层取出节点,但是不能保持层次关系,使用xpath可以很好地解决问题. *** xpath技术的核心思想:迅速简洁的定位你需要查找 ...
- Could not obtain transaction-synchronized Session for current thread 错误的解决方法!
BsTable bsTable = new BsTable(); // String time = request.getParameter("date"); String tim ...
- ruby URI类
一. URI require 'uri' uri = URI("http://foo.com/posts?id=30&limit=5#time=1305298413") # ...
- 实验吧编程题python
网址:http://ctf5.shiyanbar.com/jia 之后第一步就是刷新一下网页,发现给的公式会变,(废话,要不直接算数不就行了...)但是格式不会变. 所以那就暴力一点好了,我们看一下这 ...
- Nodejs模块初始化
模块初始化 一个模块中的JS代码仅在模块第一次被使用时执行一次,并在执行过程中初始化模块的导出对象.之后,缓存起来的导出对象被重复利用. 主模块 通过命令行参数传递给NodeJS以启动程序的模块被称为 ...
- HASH算法小结
一.简述 HASH算法的本质是特征提取——将某种不太好表示的特征,通过某种压缩的方式映射成一个值.这样,就可以优雅解决一部分难以解决的特征统计问题. 同时考虑到hash算法的本质是个概率算法,因此并不 ...
- CPU计算密集型和IO密集型
CPU计算密集型和IO密集型 第一种任务的类型是计算密集型任务,其特点是要进行大量的计算,消耗CPU资源,比如计算圆周率.对视频进行高清解码等等,全靠CPU的运算能力.这种计算密集型任务虽然也可以用多 ...
- P2212 [USACO14MAR]浇地Watering the Fields
P2212 [USACO14MAR]浇地Watering the Fields 题目描述 Due to a lack of rain, Farmer John wants to build an ir ...
- P1886 滑动窗口(单调队列)
P1886 滑动窗口 题目描述 现在有一堆数字共N个数字(N<=10^6),以及一个大小为k的窗口.现在这个从左边开始向右滑动,每次滑动一个单位,求出每次滑动后窗口中的最大值和最小值. 例如: ...
- Spring MVC - URL路径映射
1. 普通映射 A. @RequestMapping("/test1") B. @RequestMapping(value={"/test1", "/ ...