码迷,mamicode.com
首页 > 其他好文 > 详细

Codeforces 750 F:New Year and Finding Roots

时间:2019-02-15 15:44:20      阅读:195      评论:0      收藏:0      [点我收藏+]

标签:print   需要   ble   深度   int   printf   main   递归   pre   

传送门
首先如果一开始就找到了一个叶子,那么暴力去递归找它的父亲,每次随机一个方向(除了已知的儿子)走深度次,如果走到了一个叶子就不是这个方向
(设根的深度为 \(1\))这样子最后到达深度为 \(3\) 的点需要花费 \(11\)
注意到此时只有与该点距离不超过 \(2\) 的点可能是根,这样的没有询问过的点不超过 \(6\)
所以只要询问 \(5\) 次,一共 \(16\)
如果一开始不是叶子,那么尝试 \(dfs\) 到一个叶子,最后再套用上面的做法
注意每次随机一个方向的时候要判断之前是否已经有一条长度为深度的链(也可以优先选择询问过的点)

# include <bits/stdc++.h>
using namespace std;
typedef long long ll;

int h, pre[233], vis[233], n, flg, rt, leaf, actur[233], tot;
vector <int> son[233];

inline void Ask(int u) {
    if (vis[u]) return;
    int cnt, i, v;
    vis[u] = 1, printf("? %d\n", u), fflush(stdout);
    scanf("%d", &cnt);
    for (i = 0; i < cnt; ++i) scanf("%d", &v), son[u].push_back(v);
    if (son[u].size() == 2) {
        rt = u, flg = 1;
        return;
    }
}

void Dfs(int cur) {
    if (leaf || flg) return;
    int i, cnt;
    Ask(cur), cnt = son[cur].size();
    if (cnt == 1) {
        leaf = cur;
        return;
    }
    if (leaf || flg) return;
    for (i = 0; i < cnt; ++i)
        if (!vis[son[cur][i]]) {
            pre[son[cur][i]] = cur, Dfs(son[cur][i]);
            return;
        }
}

inline int Check(int u, int ff, int d) {
    if (d < 0) return 0;
    Ask(u);
    if (flg) return 1;
    if (son[u].size() == 1) return d ? 0 : actur[u] = 1;
    int i;
    for (i = 0; i < 3; ++i)
        if ((son[u][i] ^ ff) && vis[son[u][i]]) {
            if (Check(son[u][i], u, d - 1)) return actur[u] = 1;
            return 0;
        }
    for (i = 0; i < 3; ++i)
        if ((son[u][i] ^ ff) && !vis[son[u][i]]) {
            if (Check(son[u][i], u, d - 1)) return actur[u] = 1;
            return 0;
        }
}

inline int Getfa(int x, int nh) {
    Ask(x);
    if (son[x].size() == 1) return son[x][0];
    if (flg) return 0;
    int p1, p2, i;
    for (i = 0; i < 3; ++i) if (actur[son[x][i]]) break;
    if (i == 0) p1 = 1, p2 = 2;
    else if (i == 1) p1 = 0, p2 = 2;
    else p1 = 0, p2 = 1;
    p1 = son[x][p1], p2 = son[x][p2];
    if (vis[p2]) swap(p1, p2);
    return Check(p1, x, h - nh - 1) ? p2 : p1;
}

void Dfs2(int u, int d) {
    if (d > 2 || flg) return;
    if (tot == 6) {
        rt = u, flg = 1;
        return;
    }
    Ask(u), ++tot;
    if (flg) return;
    int i, cnt = son[u].size();
    for (i = 0; i < cnt; ++i)
        if (!actur[son[u][i]]) Dfs2(son[u][i], d + 1);
}

inline void Solve() {
    int cur, i, nh;
    memset(pre, 0, sizeof(pre));
    memset(vis, 0, sizeof(vis));
    memset(actur, 0, sizeof(actur));
    scanf("%d", &h), n = (1 << h) - 1, leaf = flg = 0, nh = h;
    for (i = 1; i <= n; ++i) son[i].clear();
    cur = rand() % n + 1, Dfs(cur);
    if (flg) {
        printf("! %d\n", rt), fflush(stdout);
        return;
    }
    cur = leaf, actur[cur] = 1;
    while (nh > 3) {
        cur = Getfa(cur, nh), --nh, actur[cur] = 1;
        if (flg) {
            printf("! %d\n", rt), fflush(stdout);
            return;
        }
    }
    tot = 0, Dfs2(cur, 0);
    printf("! %d\n", rt), fflush(stdout);
}

int main() {
    srand(time(NULL));
    int test;
    scanf("%d", &test);
    while (test--) Solve();
    return 0;
}

Codeforces 750 F:New Year and Finding Roots

标签:print   需要   ble   深度   int   printf   main   递归   pre   

原文地址:https://www.cnblogs.com/cjoieryl/p/10383517.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!