题目链接
分析:
如果每次删除非根的叶子结点,最多$lfloor frac{n}{2}
floor$ 次就能找到 $root$。
+ 最坏极端情况:满二叉树,每次删除底层的最右边两个叶子结点;
+ 最快极端情况:线性树,一次得到 $root$,且后面不再改变;
代码:
#include <bits/stdc++.h>
#define pb push_back
using namespace std;
const int N=1010;
vector<int>pic[N];
int degree[N];
bool vis[N];
queue<int>que;
int main()
{
int n,u,v;
scanf("%d",&n);
for(int i=1;i<n;i++)
{
scanf("%d%d",&u,&v);
pic[u].pb(v);
pic[v].pb(u);
degree[u]++;
degree[v]++;
}
for(int i=1;i<=n;i++)
{
if(degree[i]==1)
{
que.push(i);
degree[i]--;
}
}
for(int i=1;i<=n/2;i++)
{
int a,b,c;
a=que.front();
que.pop();
b=que.front();
que.pop();
printf("? %d %d
",a,b);
cout.flush();
scanf("%d",&c);
if(c==a||c==b)
{
vis[0]=1;
printf("! %d
",c);
cout.flush();
break;
}
for(int i=0;i<pic[a].size();i++)
degree[pic[a][i]]--;
for(int i=0;i<pic[b].size();i++)
degree[pic[b][i]]--;
vis[a]=1;
vis[b]=1;
for(int i=1;i<=n;i++)
{
if(degree[i]==1)
{
que.push(i);
degree[i]--;
}
}
}
//当n为奇数的时候还有一个点
if(!vis[0])
{
for(int i=1;i<=n;i++)
{
if(!vis[i])
{
printf("! %d
",i);
cout.flush();
break;
}
}
}
return 0;
}