P5597 【XR-4】复读 思维题 +二叉树合并

it2024-03-17  55

题意:

戳这里查看

分析:

由于这是一个无限大的完全二叉树,所以不合法的方案仅存在于跳到根节点的父亲这一种,且由于指令会无限重复,所以我们必须保证指令会使得离开被标记的子树的时候,所有被标记的点已经全部访问完,因为我们不会折返回去向上跳的

那么我们考虑枚举它是经过哪条路径,从哪个点离开整颗子树的,只要保证在走这条路经的同时遍历完所有的点,且由于指令会无限重复,所以我们对于路径上每一个点,将所有的子树求一个形态上的并集,只要使得整个并集能被访问,那么所有的点都会被访问到,最后的答案就是 ( c n t − 1 ) ∗ 2 − d e p (cnt-1)*2-dep (cnt1)2dep,其中 c n t cnt cnt是并集的树上节点数, d e p dep dep为我们枚举的离开的点的深度

代码:

#include<bits/stdc++.h> using namespace std; namespace zzc { const int maxn = 2e3+5; int ans=1e9+7,cnt,cur,rt,pos; char ch[maxn],pth[maxn]; struct tree { int lc,rc; }f[maxn],g[maxn]; void build(int &x) { if(!x) x=++cnt; int t=ch[pos++]-'0'; if(t&1) build(f[x].lc); if(t&2) build(f[x].rc); } void merge(int &x,int y) { if(!x) x=++cnt; if(y==cur) return ; if(f[y].lc) merge(g[x].lc,f[y].lc); if(f[y].rc) merge(g[x].rc,f[y].rc); } void solve(int u,int dep) { if(u!=1) { memset(g,0,sizeof(g)); cur=cnt=1; while(cur) { const int t=cur; for(int i=0;i<dep;i++) { cur=pth[i]=='l'?f[cur].lc:f[cur].rc; } merge(rt=1,t); } ans=min(ans,(cnt-1)*2-dep); } pth[dep]='l'; if(f[u].lc) solve(f[u].lc,dep+1); pth[dep]='r'; if(f[u].rc) solve(f[u].rc,dep+1); } void work() { scanf("%s",ch);pos=0;cnt=1; build(rt=1); solve(1,0); printf("%d\n",ans); } } int main() { zzc::work(); return 0; }
最新回复(0)