洛谷 P3549 [POI2013]MUL-Multidrink 题解

题目链接:P3549 [POI2013]MUL-Multidrink

题目大意:给一棵树,每次步伐大小只能为 (1)(2),要求不重复的遍历 (n) 个节点,且起点为 (1),终点为 (n)


题解:首先我们将 (1)(n) 的链拎出来,然后我们发现如果一个点挂了一堆叶子可以暂时先不管它,删去叶子后的每一个节点最多有两棵子树,并且必然应当是毛毛虫(一条链周围挂一堆叶子),如果一个点挂了两个毛毛虫,那么这个点的前面和后面都应当有没有叶子节点的链上点才可以,然后我们就把无解的情况判掉了,接下来只需要根据上面的分类讨论来把构造写出来就可以了。

时间复杂度 (O(n))

代码:

#include <vector>
#include <cstdio>
#include <algorithm>
const int Maxn=500000;
int n;
int deg[Maxn+5];
int head[Maxn+5],arrive[Maxn<<1|5],nxt[Maxn<<1|5],tot;
std::vector<int> g[Maxn+5];
int pre[Maxn+5];
void add_edge(int from,int to){
	arrive[++tot]=to;
	nxt[tot]=head[from];
	head[from]=tot;
}
int p[Maxn+5],p_len;
namespace Find_P{
	int fa[Maxn+5];
	void init_dfs(int u){
		for(int i=head[u];i;i=nxt[i]){
			int v=arrive[i];
			if(v==fa[u]){
				continue;
			}
			fa[v]=u;
			init_dfs(v);
		}
	}
	void work(){
		init_dfs(1);
		int u=n;
		while(u!=1){
			p[++p_len]=u;
			u=fa[u];
		}
		p[++p_len]=u;
		std::reverse(p+1,p+1+p_len);
	}
}
bool check(int u,int fa){
	int num=0;
	for(int i=head[u];i;i=nxt[i]){
		int v=arrive[i];
		if(v==fa||deg[v]==1){
			continue;
		}
		if(num>0||!check(v,u)){
			return 0;
		}
		num++;
	}
	return 1;
}
bool in_line[Maxn+5];
bool no_son[Maxn+5];
int son_num[Maxn+5];
int find_a_son(int u,int t=0){
	for(int i=head[u];i;i=nxt[i]){
		int v=arrive[i];
		if(!in_line[v]&&v!=t){
			return v;
		}
	}
	return -1;
}
int find_a_leaf(int u){
	for(int i=head[u];i;i=nxt[i]){
		int v=arrive[i];
		if(!in_line[v]&&deg[v]==1){
			return v;
		}
	}
	return find_a_son(u);
}
int ans_lis[Maxn+5],ans_len;
int qu[Maxn+5],qu_t;
int tmp_lis[Maxn<<1|5],tmp_len;
void find_a_line(int u,int fa){
	qu[++qu_t]=u;
	for(int i=head[u];i;i=nxt[i]){
		int v=arrive[i];
		if(v==fa){
			continue;
		}
		if(deg[v]==1){
			g[u].push_back(v);
			pre[v]=u;
		}
		else{
			find_a_line(v,u);
		}
	}
}
void add_a_star(int u,int v_1=0,int v_2=0){
	for(int i=0;i<(int)g[u].size();i++){
		int v=g[u][i];
		if(v==v_1||v==v_2){
			continue;
		}
		ans_lis[++ans_len]=v;
	}
}
int get_lst(int x){
	return x==1?tmp_len:x-1;
}
int get_nxt(int x){
	return x==tmp_len?1:x+1;
}
void find_path(int u,int S,int T){
	ans_lis[++ans_len]=S;
	if(S==T){
		return;
	}
	qu_t=0;
	qu[++qu_t]=u;
	for(int i=head[u];i;i=nxt[i]){
		int v=arrive[i];
		if(in_line[v]){
			continue;
		}
		if(deg[v]==1){
			g[u].push_back(v);
			pre[v]=u;
		}
		else{
			std::reverse(qu+1,qu+1+qu_t);
			find_a_line(v,u);
		}
	}
	for(int i=1;i<=qu_t;i++){
		tmp_lis[i]=(i&1)?qu[i]:-qu[i];
		tmp_lis[qu_t+qu_t-i+1]=-tmp_lis[i];
	}
	tmp_len=0;
	for(int i=1;i<=qu_t+qu_t;i++){
		if(tmp_lis[i]<0){
			if(g[-tmp_lis[i]].empty()){
				continue;
			}
		}
		tmp_lis[++tmp_len]=tmp_lis[i];
	}
	int A,B;
	if(deg[S]>1){
		A=S;
	}
	else{
		A=-pre[S];
	}
	if(deg[T]>1){
		B=T;
	}
	else{
		B=-pre[T];
	}
	int pos=-1;
	for(int i=1;i<=tmp_len;i++){
		if(tmp_lis[i]==A){
			pos=i;
			break;
		}
	}
	if(A<0){
		add_a_star(-A,S,T);
	}
	if(tmp_lis[get_lst(pos)]==B){
		for(int j=get_nxt(pos);tmp_lis[j]!=B;j=get_nxt(j)){
			if(tmp_lis[j]>0){
				ans_lis[++ans_len]=tmp_lis[j];
			}
			else{
				add_a_star(-tmp_lis[j]);
			}
		}
	}
	else{
		for(int j=get_lst(pos);tmp_lis[j]!=B;j=get_lst(j)){
			if(tmp_lis[j]>0){
				ans_lis[++ans_len]=tmp_lis[j];
			}
			else{
				add_a_star(-tmp_lis[j]);
			}
		}
	}
	if(B<0&&A!=B){
		add_a_star(-B,S,T);
	}
	ans_lis[++ans_len]=T;
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<n;i++){
		int u,v;
		scanf("%d%d",&u,&v);
		add_edge(u,v);
		add_edge(v,u);
		deg[u]++,deg[v]++;
	}
	Find_P::work();
	for(int i=1;i<=p_len;i++){
		in_line[p[i]]=1;
	}
	for(int i=1;i<=p_len;i++){
		int u=p[i];
		no_son[u]=1;
		for(int j=head[u];j;j=nxt[j]){
			int v=arrive[j];
			if(in_line[v]){
				continue;
			}
			no_son[u]=0;
			if(deg[v]==1){
				continue;
			}
			son_num[u]++;
			if(son_num[u]>2){
				puts("BRAK");
				return 0;
			}
			if(!check(v,u)){
				puts("BRAK");
				return 0;
			}
		}
	}
	int tag_free=0;
	for(int i=1;i<=p_len;i++){
		int u=p[i];
		if(no_son[u]){
			tag_free=1;
		}
		else if(son_num[u]==2){
			if(tag_free!=1){
				puts("BRAK");
				return 0;
			}
			tag_free=2;
		}
	}
	if(tag_free==2){
		puts("BRAK");
		return 0;
	}
	int S=p[1],T;
	if(no_son[p[1]]){
		T=p[1];
	}
	else{
		T=find_a_son(p[1]);
	}
	find_path(p[1],S,T);
	for(int i=2;i<=p_len;i++){
		int u=p[i];
		if(no_son[u]){
			S=T=u;
		}
		else if(!in_line[T]){
			S=u;
			T=find_a_leaf(u);
		}
		else{
			S=find_a_leaf(u);
			T=son_num[u]<2?u:find_a_son(u,S);
		}
		find_path(u,S,T);
	}
	if(ans_len!=n||ans_lis[ans_len]!=n){
		puts("BRAK");
		return 0;
	}
	puts("TAK");
	for(int i=1;i<=n;i++){
		printf("%d
",ans_lis[i]);
	}
	return 0;
}
原文地址:https://www.cnblogs.com/withhope/p/14521805.html