CodeForces-1305D Kuroni and the Celebration【树】

题目链接

分析:

如果每次删除非根的叶子结点,最多$\lfloor \frac{n}{2} \rfloor$ 次就能找到 $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\n",a,b);
        cout.flush();
        scanf("%d",&c);
        if(c==a||c==b)
        {
            vis[0]=1;
            printf("! %d\n",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\n",i);
                cout.flush();
                break;
            }
        }
    }
    return 0;
}

posted @ 2020-03-04 20:51  xzx9  阅读(214)  评论(0编辑  收藏  举报