题目链接:https://www.luogu.org/problem/P5022
这道题目一开始看的时候没有思路,但是看到数据范围里面有一个:
\(m = n-1\) 或 \(m = n\) ,一下子有了思路。
当 \(m = n-1\) 时,这就是一棵树,以1为根节点进行搜索,每次优先访问编号小的点即可。
当 \(m = n\) 时,可知只有一个环,找到环中对应的所有边,然后遍历每一条环中的边,假设删除它,然后就变成了一棵树。
时间复杂度为:\(O(n^2)\) 。
实现代码如下:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 5050;
struct Node {
int u, v, id;
Node() {}
Node(int _u, int _v, int _id) { u = _u; v = _v; id = _id; }
} edge[maxn*2], loop_edge[maxn];
vector<Node> g[maxn];
int n, m, p[maxn], pe[maxn], cnt, depth[maxn];
bool vis[maxn], vise[maxn*2], marked[maxn*2];
int ans_seq[maxn], tmp_seq[maxn], ans_cnt, tmp_cnt;
bool cmp(Node a, Node b) {
return a.v < b.v;
}
void find_loop(int u, int pre, int d) {
vis[u] = true;
depth[u] = d;
int sz = g[u].size();
for (int i = 0; i < sz; i ++) {
int v = g[u][i].v, id = g[u][i].id;
if (v == pre) continue;
if (!vis[v]) {
vise[id] = vise[id^1] = true;
p[v] = u;
pe[v] = id;
find_loop(v, u, d+1);
}
}
}
void select_loop_edges(int u, int v, int id) {
loop_edge[cnt++] = Node(u, v, id);
while (u != v) {
if (depth[u] > depth[v]) {
loop_edge[cnt++] = Node(p[u], u, pe[u]);
u = p[u];
}
else if (depth[u] < depth[v]) {
loop_edge[cnt++] = Node(p[v], v, pe[v]);
v = p[v];
}
else {
loop_edge[cnt++] = Node(p[u], u, pe[u]);
u = p[u];
loop_edge[cnt++] = Node(p[v], v, pe[v]);
v = p[v];
}
}
}
void dfs(int u, int pre) {
tmp_seq[tmp_cnt++] = u;
int sz = g[u].size();
for (int i = 0; i < sz; i ++) {
int v = g[u][i].v, id = g[u][i].id;
if (v == pre || marked[id] || marked[id^1]) continue;
dfs(v, u);
}
}
void final_check() {
bool flag = false;
if (ans_seq[0]) {
for (int i = 0; i < n; i ++) {
if (ans_seq[i] > tmp_seq[i]) { flag = true; break; }
else if (ans_seq[i] < tmp_seq[i]) break;
}
}
else
flag = true;
if (flag) for (int i = 0; i < n; i ++) ans_seq[i] = tmp_seq[i];
}
int main() {
scanf("%d%d", &n, &m);
for (int i = 0; i < m; i ++) {
int u, v, w;
scanf("%d%d", &u, &v);
g[u].push_back(Node(u, v, i*2));
g[v].push_back(Node(v, u, i*2+1));
edge[i*2] = Node(u, v, i*2);
edge[i*2+1] = Node(v, u, i*2+1);
}
for (int i = 1; i <= n; i ++) sort(g[i].begin(), g[i].end(), cmp);
if (m == n) {
find_loop(1, -1, 1);
for (int i = 0; i < 2*m; i += 2) {
if (!vise[i]) {
int u = edge[i].u, v = edge[i].v;
select_loop_edges(u, v, i);
break;
}
}
for (int i = 0; i < cnt; i ++) {
marked[loop_edge[i].id] = marked[loop_edge[i].id^1] = true;
tmp_cnt = 0;
dfs(1, -1);
final_check();
marked[loop_edge[i].id] = marked[loop_edge[i].id^1] = false;
}
}
else { // m == n-1
dfs(1, -1);
final_check();
}
for (int i = 0; i < n; i ++) {
if (i) putchar(' ');
printf("%d", ans_seq[i]);
}
puts("");
return 0;
}