版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
正题
好题
因为经过一次循环操作后的结束位置深度一定严格大于起始点,那么说明这次循环操作必须遍历除结束位置子树且在起始点子树内的所有有效点。
我们暴力枚举第一次操作后的结束位置,然后递推把后面几次的结束位置找出来,它们同时也是下一次操作的起始点,然后从这些点开始,把当前必须遍历的点提出来,做一次并,就是一次操作遍历子树的亚子。
假如这个并的大小为size,那么答案就是(size-1)*2-dep,dep指的是每次结束点的深度-起始点的深度。
#include<bits/stdc++.h>
using namespace std;
const int N=2010;
bool tf[N];
char s[N];
int p[N],son[N][2],n,tot=0,rt[N],size;
int tt[N][N];
int ans=1e9;
int build(){
int t;tot++;
int now=tot;t=s[tot-1]-'0';
if(t&1) son[now][0]=tot+1,build();
if(t&2) son[now][1]=tot+1,build();
return -1;
}
void get_size(int dep){
bool we=false;size++;
for(int i=1;i<=rt[0];i++) we|=(!tf[son[rt[i]][0]]);
if(we){
for(int i=1;i<=rt[0];i++) tt[dep][i]=rt[i],rt[i]=son[rt[i]][0];
get_size(dep+1);
for(int i=1;i<=rt[0];i++) rt[i]=tt[dep][i];
}
we=false;
for(int i=1;i<=rt[0];i++) we|=(!tf[son[rt[i]][1]]);
if(we){
for(int i=1;i<=rt[0];i++) tt[dep][i]=rt[i],rt[i]=son[rt[i]][1];
get_size(dep+1);
for(int i=1;i<=rt[0];i++) rt[i]=tt[dep][i];
}
return ;
}
void get_ans(int x,int dep){
if(x!=1){
rt[0]=0;
memset(tf,false,sizeof(tf));tf[0]=true;tf[1]=true;tf[x]=true;
rt[++rt[0]]=1;rt[++rt[0]]=x;
int now=x,t=0;
while(1){
bool we=false;t=0;
while(t<dep){
now=son[now][p[t]];
if(!now) {we=true;break;}
t++;
}
if(we) break;
tf[now]=true;
rt[++rt[0]]=now;
}
size=0;get_size(0);
ans=min(ans,size*2-dep);
}
if(son[x][0]) p[dep]=0,get_ans(son[x][0],dep+1);
if(son[x][1]) p[dep]=1,get_ans(son[x][1],dep+1);
return ;
}
int main(){
scanf("%s",s);
build();
get_ans(1,0);
printf("%d\n",ans);
}