题目大意:给一棵树,每次步伐大小只能为1或2,要求不重复的遍历n个节点,且起点为1,终点为n
首先推荐Claris的题解,讲得还是挺详细的
其次推荐算是此题题解的英文论文,可以在看Claris题解的同时补充一下
不想看英文论文的就可以看我的补充了....
1.首先证明当一个节点拥有三个或以上的non-trivial的毛毛虫时是无解的
假设我们给予这种情况最大的自由度,即遍历这段子树的时候可以任选起点为根或深度为1的点
但是无论如何,当我们进入第三条non-trivial的毛毛虫时,入口一定是深度为1的点,并且此时根也已经走过了,所以这时一定是出不来的,路径会断在这颗子树里
又因为n节点一定在主干上,所以不会出现路径断在里面还有解的情况
2.接着证明为什么两个B节点之间必须有FREE节点
因为遍历一个B节点的子树时,一定是从主干中的上一个点进入一个深度为1的点,然后遍历完这个毛毛虫再经过B节点进入另一个毛毛虫,所以出来的时候一定在B节点的下一个主干节点
假设两个B节点中间都是A且非FREE节点,那么永远从一个节点的子树出来的时候都会走到下一个主干节点,当最后一次走到B节点上时,就无解了!
而如果有FREE节点的存在,相当于可以“缓一步”,变成可以重新优先进入深度为1的节点了,这样才有解
3.遍历一个主干节点的子树的具体方法
这步卡死我了,Claris一句话就略过了,留了个图看起来非常简单,结果我根本写不出来TAT
大概思路就是这样,首先把两条毛毛虫的主体(即去掉叶子节点)按某种顺序连接起来,具体方法就是拿一个数组记录从当前节点到毛毛虫的尾巴路径上点的编号,如果还有另一条毛毛虫,就将此条毛毛虫翻转,这样使得这两条毛毛虫首位相接
然后考虑毛毛虫如何遍历,假设不考虑起始点和终点,应该从第一个点开始,然后遍历第二个点的腿,第三个点,第四个点的腿.....
所以当有起始限制时,我们就在序列中找到开头,然后根据结尾在开头的左右决定遍历顺序,extend函数就是遍历“腿”的过程
嗯,差不多补充完毕了.....
#include<iostream>
#include<cstdio>
#include<algorithm>
#define N 500010
using namespace std;
int to[N<<1],nxt[N<<1],pre[N],cnt,du[N];
void ae(int ff,int tt)
{
cnt++;
to[cnt]=tt;
nxt[cnt]=pre[ff];
pre[ff]=cnt;
}
int fa[N];
void build(int x)
{
int i,j;
for(i=pre[x];i;i=nxt[i])
{
j=to[i];
if(j==fa[x]) continue;
fa[j]=x;
build(j);
}
}
bool checkchain(int x,int ff)
{
int i,j,total=0;
for(i=pre[x];i;i=nxt[i])
{
j=to[i];
if(j==ff||du[j]==1) continue;
if(!checkchain(j,x)) return false;
total++;
if(total==2) return false;
}
return true;
}
int a[N],tot,sub[N];
bool spc[N],fre[N];
void cal(int x)
{
int i,j;
for(i=pre[x];i;i=nxt[i])
{
j=to[i];
if(spc[j]) continue;
fre[x]=false;
if(du[j]==1) continue;
sub[x]++;
if(sub[x]==3) {puts("BRAK");exit(0);}
if(!checkchain(j,x)) {puts("BRAK");exit(0);}
}
}
int sbson(int x)
{
int i,j;
for(i=pre[x];i;i=nxt[i])
{
j=to[i];
if(!spc[j]) return j;
}
}
int yzson(int x)
{
int i,j;
for(i=pre[x];i;i=nxt[i])
{
j=to[i];
if(!spc[j]&&du[j]==1) return j;
}
return sbson(x);
}
int diffson(int x,int xx)
{
int i,j;
for(i=pre[x];i;i=nxt[i])
{
j=to[i];
if(!spc[j]&&j!=xx) return j;
}
}
int ans[N],cn;
int q[N],t;
int b[N],tt,FA[N];
int left(int x)
{
if(x==1) return tt;
return x-1;
}
int right(int x)
{
if(x==tt) return 1;
return x+1;
}
int TO[N<<1],NXT[N<<1],PRE[N],CNT;
void AE(int ff,int tt)
{
FA[tt]=ff;
CNT++;
TO[CNT]=tt;
NXT[CNT]=PRE[ff];
PRE[ff]=CNT;
}
void findchain(int x,int ff)
{
t++;q[t]=x;
int i,j;
for(i=pre[x];i;i=nxt[i])
{
j=to[i];
if(j==ff) continue;
if(du[j]==1) AE(x,j);
else findchain(j,x);
}
}
void extend(int x,int A,int B)
{
int i,j;
for(i=PRE[x];i;i=NXT[i])
{
j=TO[i];
if(j==A||j==B) continue;
cn++;ans[cn]=j;
}
}
void getpath(int x,int S,int T)
{
cn++;ans[cn]=S;
if(S==T)return;
int i,j,A,B;
t=1;q[1]=x;
for(i=pre[x];i;i=nxt[i])
{
j=to[i];
if(spc[j]) continue;
if(du[j]==1) AE(x,to[i]);
else
{
reverse(q+1,q+t+1);
findchain(j,x);
}
}
for(i=1;i<=t;i++)
{
b[i]=i&1?q[i]:-q[i];
b[2*t-i+1]=-b[i];
}
tt=0;
for(i=1;i<=2*t;i++)
{
if(b[i]<0&&!PRE[-b[i]]) continue;
tt++;
b[tt]=b[i];
}
if(du[S]>1) A=S;
else A=-FA[S];
if(du[T]>1) B=T;
else B=-FA[T];
for(i=1;i<=tt;i++)
if(b[i]==A) break;
if(A<0) extend(-A,S,T);
if(b[left(i)]==B)
{
for(j=right(i);b[j]!=B;j=right(j))
if(b[j]>0) cn++,ans[cn]=b[j];
else extend(-b[j],0,0);
}
else
{
for(j=left(i);b[j]!=B;j=left(j))
if(b[j]>0) cn++,ans[cn]=b[j];
else extend(-b[j],0,0);
}
if(B<0&&A!=B)
extend(-B,S,T);
cn++;
ans[cn]=T;
}
int main()
{
int n;
int i,j,x,y;
scanf("%d",&n);
for(i=1;i<n;i++)
{
scanf("%d%d",&x,&y);
ae(x,y);ae(y,x);
du[x]++;du[y]++;
}
build(1);
i=n;
while(i!=1) tot++,a[tot]=i,i=fa[i];
tot++;a[tot]=1;
reverse(a+1,a+tot+1);
for(i=1;i<=tot;i++) spc[a[i]]=true;
for(i=1;i<=tot;i++)
{
fre[a[i]]=true;
cal(a[i]);
}
bool fl=false,never=true;
for(i=1;i<=tot;i++)
{
if(fre[a[i]]) fl=true;
else if(sub[a[i]]==2)
{
never=false;
if(fl) fl=false;
else {puts("BRAK");return 0;}
}
}
if(!fl&&!never) {puts("BRAK");return 0;}
int S,T;
if(fre[1]) S=1,T=1;
else S=1,T=sbson(1);
getpath(1,S,T);
for(i=2;i<=tot;i++)
{
x=a[i];
if(fre[x]) S=T=x;
else if(spc[T])
{
S=yzson(x);
if(sub[x]!=2) T=x;
else T=diffson(x,S);
}
else S=x,T=yzson(x);
getpath(x,S,T);
}
// for(i=1;i<=n;i++)cout<<ans[i]<<' ';
if(ans[n]!=n) {puts("BRAK");return 0;}
for(i=1;i<=n;i++)
printf("%d\n",ans[i]);
}