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;
}
posted @ 2021-04-28 10:05  wwwsfff  阅读(77)  评论(0编辑  收藏  举报