CodeForces 750F. New Year and Finding Roots

This is an interactive problem. In the interaction section below you will find the information about flushing the output.

The New Year tree of height h is a perfect binary tree with vertices numbered 1 through 2h - 1 in some order. In this problem we assume that h is at least 2. The drawing below shows one example New Year tree of height 3:

Polar bears love decorating the New Year tree and Limak is no exception. To decorate the tree, he must first find its root, i.e. a vertex with exactly two neighbours (assuming that h ≥ 2). It won't be easy because Limak is a little bear and he doesn't even see the whole tree. Can you help him?

There are t testcases. In each testcase, you should first read h from the input. Then you can ask at most 16 questions of format "? x" (without quotes), where x is an integer between 1 and 2h - 1, inclusive. As a reply you will get the list of neighbours of vertex x (more details in the "Interaction" section below). For example, for a tree on the drawing above after asking "? 1" you would get a response with 3 neighbours: 45 and 7. Your goal is to find the index of the root y and print it in the format "! y". You will be able to read h for a next testcase only after printing the answer in a previous testcase and flushing the output.

Each tree is fixed from the beginning and it doesn't change during your questions.

Input

The first line of the input contains a single integer t (1 ≤ t ≤ 500) — the number of testcases.

At the beginning of each testcase you should read from the input a single integer h (2 ≤ h ≤ 7) — the height of the tree. You can't read the value of h in a next testcase until you answer a previous testcase.

Interaction

To ask a question about neighbours of vertex x, print "? x" (without quotes) on a separate line. Note, you must print an end-of-line character after the last character of the line and flush your output to get a response.

The response will consist of two lines. The first line will contain a single integer k (1 ≤ k ≤ 3) — the number of neighbours of vertex x. The second line will contain k distinct integers t1, ..., tk (1 ≤ t1 < ... < tk ≤ 2h - 1) — indices of neighbours of vertex x, gives in the increasing order.

After asking at most 16 questions you have to say y — the index of the root. Print "! y" (without quotes) and an end-of-line character, and flush the output.

Each tree is fixed from the beginning and it doesn't change during your questions.

You can get Idleness Limit Exceeded if you don't print anything or if you forget to flush the output.

To flush you can use (just printing a query/answer and end-of-line):

  • fflush(stdout) in C++;
  • System.out.flush() in Java;
  • stdout.flush() in Python;
  • flush(output) in Pascal;
  • See the documentation for other languages.

In any moment if the program reads h = 0 or k = 0 it should immediately terminate normally (for example, calling exit(0)). It means that the system detected incorrect request/output from your program and printed 0 because if can't process your requests anymore. In this case you'll receive verdict "Wrong Answer", but if you ignore case h = 0 or k = 0 it could lead to "Runtime Error", "Time/Memory limit exceeded" or any other verdict because your program could read a trash from the closed input stream.

Hacking. To hack someone, use the following format:

The first line should contain a single integer t equal to 1 (only one testcase is allowed in hacks). The second line should contain a single integer h. Each of next 2h - 2 lines should contain two distinct integers ai and bi (1 ≤ ai, bi ≤ 2h - 1), denoting two nodes connected with an edge. The printed edges must form a perfect binary tree of height h.

Of course, contestant programs will not be able to see this input.

Examples
input
1
3
3
4 5 7
2
1 2
1
2
output
? 1
? 5
? 6
! 5
input
2
2
1
3
2
1 2
2
1 2
4
3
3 12 13
output
? 1
? 3
? 3
! 3
? 6
! 1
Note

In the first sample, a tree corresponds to the drawing from the statement.

In the second sample, there are two two testcases. A tree in the first testcase has height 2 and thus 3 vertices. A tree in the second testcase has height 4 and thus 15 vertices. You can see both trees on the drawing below.

搞了两三个小时终于搞出来了
我不知道怎么传图片QAQ
重新打一遍题解,记L[i]为i的邻居数
询问1->L[1]==2->print(1)
         ->L[1]==3,说明一号节点在树中间,向左右两边延伸,直到碰到叶节点L[i]=1,找出路径中点,则其深度                       dep = H - (左边节点数+右边节点数)/2
            ->L[1]==1或者上面执行完 我们就找到了一个深度为dep的点,它下面要么没有,要么已经被访问过
接下来数据分治
if( dep <= 4 )
{
dep=1直接输出
dep=2它的儿子已经被访问过(或根本没有儿子),直接跳到父亲,输出
dep=3或4 跳到父亲,bfs1或2层
注意:bfs队尾不用搞,可以减少一次询问
}
else
{
像之前一样暴力延伸
找出路径中点(注意考虑dep的影响)
递归处理
}
最坏情况
第一次:访问到dep=7的叶节点 +1次
第二次:往上跳一层后又到另一个叶节点,dep=6 +2次
第三次:同上dep=5 +3次
第四次:同上dep=4 +4次
第五次:跳到父亲 +1次 第一轮bfs有2个点进队,+2次
第六次:把队里的2个点的邻居跑一遍 +3次
剩下的最后一个邻居不用跑 正好16次
太精巧了, 甘拜下风
(我为啥写了3KB)
#include <bits/stdc++.h>

using namespace std;

const int maxn = 1000;

int H, l[maxn], a[maxn][4], q[maxn], T, head, tail;

bool used[maxn];

inline void get(int x)
{
	if( used[ x ] ) return;
	printf( "? %d\n", x );
	fflush( stdout );
	used[ x ] = true;
	scanf( "%d", &l[ x ] );
	for( int i = 1 ; i <= l[ x ] ; i++ ) scanf( "%d", &a[ x ][ i ] );
}

inline void print(int x)
{
	printf( "! %d\n", x );
	fflush( stdout );
}

inline void solve()
{
	memset( used, 0, sizeof( used ) );
	scanf( "%d", &H );
	get( 1 );
	head = tail = 20;
	if( l[ 1 ] == 2 ) { print( 1 ); return ; }
	if( l[ 1 ] == 1 ) q[ 20 ] = 1;
	else
	{
		q[ 20 ] = 1;
		q[ ++tail ] = a[ 1 ][ 1 ];
		while( true )
		{
			get( q[ tail ] );
			if( l[ q[ tail ] ] == 1 ) break;
			for( int i = 1 ; i <= l[ q[ tail ] ] ; i++ )
				if( a[ q[ tail ] ][ i ] != q[ tail - 1 ] )
				{
					q[ tail + 1 ] = a[ q[ tail ] ][ i ];
					tail++;
					break;
				}
		}
		q[ --head ] = a[ 1 ][ 2 ];
		while( true )
		{
			get( q[ head ] );
			if( l[ q[ head ] ] == 1 ) break;
			for( int i = 1 ; i <= l[ q[ head ] ] ; i++ )
				if( a[ q[ head ] ][ i ] != q[ head + 1 ] )
				{
					q[ head - 1 ] = a[ q[ head ] ][ i ];
					head--;
					break;
				}
		}
	}
	int dep = H - ( tail - head ) / 2, cur = q[ head + tail >> 1 ];
	while( true )
	{
		if( dep <= 4 )
		{
			if( dep == 1 ) { print( cur ); return ; }
			for( int i = 1 ; i <= l[ cur ] ; i++ )
				if( !used[ a[ cur ][ i ] ] )
				{
					cur = a[ cur ][ i ];
					break;
				}
			dep--;
			if( dep == 1 ) { print( cur ); return ; }
			if( dep == 2 )
			{
				int tmp[20], len = 0;
				get( cur );
				for( int i = 1 ; i <= l[ cur ] ; i++ )
					if( !used[ a[ cur ][ i ] ] )
						tmp[ ++len ] = a[ cur ][ i ];
				for( int i = 1 ; i < len ; i++ )
				{
					get( tmp[ i ] );
					if( l[ tmp[ i ] ] == 2 ) { print( tmp[ i ] ); return ; }
				}
				print( tmp[ len ] ); return ;
			}
			else
			{
				int tmp[20], len = 0;
				int tmp2[20], len2 = 0;
				get( cur );
				for( int i = 1 ; i <= l[ cur ] ; i++ )
					if( !used[ a[ cur ][ i ] ] )
						tmp[ ++len ] = a[ cur ][ i ];
				for( int i = 1 ; i <= len ; i++ )
				{
					get( tmp[ i ] );
					for( int j = 1; j <= l[ tmp[ i ] ] ; j++ )
						if( !used[ a[ tmp[ i ] ][ j ] ] )
							tmp2[ ++len2 ] = a[ tmp[ i ] ][ j ];
				}
				for( int i = 1 ; i < len2 ; i++ )
				{
					get( tmp2[ i ] );
					if( l[ tmp2[ i ] ] == 2 ) { print( tmp2[ i ] ); return ; }
				}
				print( tmp2[ len2 ] ); return ;
			}
		}
		head = tail = 0;
		q[ tail ] = cur;
		while( true )
		{
			get( q[ tail ] );
			if( l[ q[ tail ] ] == 1 && tail > 0 ) break;
			if( l[ q[ tail ] ] == 2 ) { print( q[ tail ] ); return ; }
			for( int i = 1 ; i <= l[ q[ tail ] ] ; i++ )
				if( !used[ a[ q[ tail ] ][ i ] ] )
				{
					q[ tail + 1 ] = a[ q[ tail ] ][ i ];
					tail++;
					break;
				}
		}
		int D = H - dep;
		cur = q[ tail - D >> 1 ];
		dep -= ( tail - D >> 1 );
	}
}

int main()
{
	scanf( "%d", &T );
	while( T-- ) solve();
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值