Luogu P5049 [NOIP2018 提高组] 旅行 加强版
题链
[P5049 NOIP2018 提高组] 旅行 加强版 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
分析
考虑\(n^2\)的做法:显然环上有一条边不会走,所以删掉每条边做一遍
考虑优化:(假设都在环上),
如果从u到某个点v不走比走优(因为不会回到u,所以u的子树要都走遍),当且仅当上u不存在比v大的子结点,且u之前的第一个存在大于u的子节点的点不存在比v小的子结点(注意:1所在子树的根无法再走到到1链上的点),则(u,v)要断掉
可以用set维护边集,这应该是最短的写法
找环:类似tarjan,无向图中用DFS,找到相同的节点即找到了环,依次弹出直到弹到相同的节点即为环
WA了一次:没想清楚,注意是子节点
#include<bits/stdc++.h>
using namespace std;
const int N=5e5+5;
int n,m;
set<int>V[N];
int top,st[N],fll,fir,sec;
bool fl[N];
void huan(int fa,int u) {
if(fl[u]) {
fll=u; return;
}
fl[u]=1;
for(int v:V[u]) {
if(v!=fa) {
huan(u,v);
if(fll) {
if(fll!=-1) {
st[++top]=u;
if(u==fll) {
fir=u,sec=fa;
fll=-1;
}
}
return;
}
}
}
}
void cut() {
huan(0,1);
int ban1=0,ban2=0;
auto t=V[st[top]].upper_bound(st[top-1]);
if(*t==sec) t++;
int mn=*t;
for(int i=top-1;i>1;i--) {
auto t=V[st[i]].upper_bound(st[i-1]);
if(t!=V[st[i]].end()&&*t==st[i+1]) t++;
if(t==V[st[i]].end()&&mn<st[i-1]) {
ban1=st[i],ban2=st[i-1];
break;
}
if(t!=V[st[i]].end()) mn=*t;
}
if(!ban1) {
ban1=st[top],ban2=st[1];
}
V[ban1].erase(ban2),V[ban2].erase(ban1);
}
void dgs(int fa,int u) {
printf("%d ",u);
for(int v:V[u]) {
if(v!=fa) {
dgs(u,v);
}
}
}
int main() {
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++) {
int u,v; scanf("%d%d",&u,&v);
V[u].insert(v);
V[v].insert(u);
}
if(n==m) cut();
dgs(0,1);
return 0;
}