Good Bye 2016 F.New Year and Finding Roots(交互)


題目鏈接

\(Description\)

  有一棵高度為\(h\)的滿二叉樹,點從\(1\)\(2^h-1\)編號(無序)。每次你可以詢問一個點的編號,交互庫會返回其所有鄰接點的編號。你需要在\(16\)次詢問內確定這棵樹根節點的編號。
  \(h\leq 7\)

\(Solution\)

  考慮隨便問一個點,然后任意找個相鄰點走。這樣如果不往回走,最差情況下是一直走到一個葉子,這樣找走兩遍,擴展出一條葉子到葉子的鏈,就可以往上擴展了。這樣最多擴展\(1+2+\ldots+7=28\)個點,但是確定根節點就夠了,即\(21\)個。
  還是不行。在深度比較淺時代價會比較高,但是深度淺了我們離根節點就更近。所以在離根足夠近(距離為\(2\))直接BFS。這樣代價為\(10+1+2+4=17\),但是最后一個點不需要查知道了,代價為\(16\)

  思路很好理解,但是代碼好難寫啊。。棄療了。參考個吧。orz\(yanQval\).
  要對初始點DFS兩次,不管路徑如何,我們記下兩條路徑經過點數\(c_1,c_2\),其深度就是\(\frac{c_1+c_2}{2}+1\)。如果有一次是向根節點延伸(\(c_1\neq c_2\)),就可以直接跳到經過路徑上最靠近根的點。
  之后保證每次向上走,用之前的深度和新路徑的點數同樣可以跳。最后手動BFS。

#include <cstdio>
#include <cctype>
#include <cstring>
#include <algorithm>
#define gc() getchar()
const int N=150;

int h,dgr[N],son[N][3],A1[N],A2[N];
bool vis[N];

inline int read()
{
	int now=0;register char c=gc();
	for(;!isdigit(c);c=gc());
	for(;isdigit(c);now=now*10+c-'0',c=gc());
	return now;
}
#define Check(x) if(dgr[x]==2) return x
inline void Query(int x)
{
	vis[x]=1;
	printf("? %d\n",x), fflush(stdout);
	dgr[x]=read();
	for(int i=0; i<dgr[x]; ++i) son[x][i]=read();
}
inline int Step(int x)
{
	for(int i=0; i<dgr[x]; ++i) if(!vis[son[x][i]]) return son[x][i];
	return son[x][0];
}
int Solve()
{
	memset(vis,0,sizeof vis);
	int h=read(), x=rand()%((1<<h)-1)+1, dep;
	Query(x); Check(x);
	if(dgr[x]==1) dep=1;
	else
	{
		int cnt1=0, cnt2=0;
		for(int v=Step(x); ; v=Step(v))
		{
			Query(v), A1[++cnt1]=v; Check(v);
			if(dgr[v]==1) break;
		}
		for(int v=Step(x); ; v=Step(v))
		{
			Query(v), A2[++cnt2]=v; Check(v);
			if(dgr[v]==1) break;
		}
		dep=(cnt1+cnt2>>1)+1;
		if(cnt1>cnt2) x=A1[cnt1-dep+1];
		else if(cnt1<cnt2) x=A2[cnt2-dep+1];
	}
	for(int cnt=0; dep<4/*not 5*/; cnt=0)
	{
		for(int v=Step(x); ; v=Step(v))
		{
			Query(v), A1[++cnt]=v; Check(v);
			if(dgr[v]==1) break;
		}
		dep=dep+cnt+1>>1, x=A1[cnt-dep+1];
	}
	int a,b,c,d,e;
	if(dep<h)
	{
		x=Step(x), Query(x); Check(x);
	}
	if(dep<h-1)
	{
		a=Step(x), Query(a); Check(a);
		b=Step(x), Query(b); Check(b);
	}
	if(dep<h-2)
	{
		c=Step(a), Query(c); Check(c);
		d=Step(a), Query(d); Check(d);
		e=Step(b), Query(e); Check(e);
		return Step(b);
	}
	return x;
}

int main()
{
	for(int T=read(); T--; printf("! %d\n",Solve()),fflush(stdout));
	return 0;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM