P5597 【XR-4】復讀 思維題 +二叉樹合併

youth518發表於2020-10-21

題意:

戳這裡檢視

分析:

由於這是一個無限大的完全二叉樹,所以不合法的方案僅存在於跳到根節點的父親這一種,且由於指令會無限重複,所以我們必須保證指令會使得離開被標記的子樹的時候,所有被標記的點已經全部訪問完,因為我們不會折返回去向上跳的

那麼我們考慮列舉它是經過哪條路徑,從哪個點離開整顆子樹的,只要保證在走這條路經的同時遍歷完所有的點,且由於指令會無限重複,所以我們對於路徑上每一個點,將所有的子樹求一個形態上的並集,只要使得整個並集能被訪問,那麼所有的點都會被訪問到,最後的答案就是 ( 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;
}

相關文章