zoukankan      html  css  js  c++  java
  • 洛谷 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;
    }
    
  • 相关阅读:
    x-ua-compatible的实践
    在iframe中使用cookie需要注意
    border在IE6设置transparent无效
    开发过程中的一点领悟(2)
    mouseover和mouseout、mouseenter和mouseleave
    scrollWidth的巧妙运用
    后一个div无法遮挡住前一个有img的div
    ie6并不是不支持!important
    window.parent
    (转)nmake学习笔记
  • 原文地址:https://www.cnblogs.com/withhope/p/14521805.html
Copyright © 2011-2022 走看看