题解 P5536 【XR-3】核心城市

· · 题解

P5536 【XR-3】核心城市

解法

看了下好像题解都是写以直径为基础的算法,我来讲一下鄙人自己对于这道题的认识。

如图,这是一颗满足题目要求的无根树

这时,如果 k=2 那么显然 2 号城市和 4 号城市会成为核心城市,原因是此时所有非叶子节点都是非核心城市,答案为 1。

那么来看看下面这个图:

先设它的根为 1 号节点。

让我们看看 k=13 时是怎样的,很明显,所有的城市都可以成为核心城市,所以答案为0。

那当 k=7 时呢(有 6 个城市被排出在外时)?

你可以这样,此时答案是1且最优。

你也可以这样,此时答案是1且最优。

多画几个图,不难发现,当 5 \leq k \leq 12 时,答案都是1,此时所有非核心城市都有一个共同点:都是叶子节点(如下图)。

于是我们就可以想到由叶子节点一层层往内推统计城市个数,最后答案就是所有非核心城市的深度的最大值,这里的深度是由叶子节点为为第一层往根上推的,而根是什么根本无所谓。

用拓扑排序即可想法很像。

代码

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

const int maxn = 100005;
const int maxe = 200005;

struct reader {
    template <typename Type>
    reader&operator>> (Type&ret) {
        register int f = 1; ret = 0; register char ch = getchar ();
        for (;!isdigit (ch); ch = getchar ()) if (ch=='-') f=-f;
        for (; isdigit (ch); ch = getchar ()) ret = (ret << 1) + (ret << 3) + ch - '0';
        ret *= f; return *this;
    }
}fin;

int N, K, x, y, du[maxn], ans;
int lnk[maxn], nxt[maxe], son[maxe], tot;
void add_e (register int x, register int y) {
    son[++tot] = y; nxt[tot] = lnk[x];
    lnk[x] = tot; du[y]++; return;
} // 邻接表存图
int que[maxn], dep[maxn], L, R; bool vis[maxn];
//这里的变量和数组都是字面意思,初中的教练一直要求代码要可以望文生义
void topo () {
    while (L ^ R) {
        L++;
        for (register int j = lnk[que[L]]; j; j = nxt[j]) {
            if (--du[son[j]] != 1) continue
            if (vis[son[j]]) continue; vis[son[j]] = true;
            dep[son[j]] = dep[que[L]] + 1; ans = max (ans, dep[son[j]]);
            //这里随时刷新 ans 的最大值
            que[++R] = son[j]; K--; if (K < 1) return;
        }
    }
    return;
} //其他的就是普通的 topo 写法了

int main () {
    freopen("P5536.in","r",stdin);
    freopen("P5536.out","w",stdout);
    fin >> N >> K; K = N - K; // 将 K 的含义转为非核心城市的个数
    for (register int i = 2; i <= N; i++) {
        fin >> x >> y;
        add_e (x, y); add_e (y, x);
    }   L = R = 0; ans = 0; // 建图
    for (register int i = 1; i <= N; i++) if (du[i] == 1 && K >= 1)
    que[++R] = i, vis[i] = true, K--, ans = 1, dep[i] = 1;
    //这一块原本是应该放在topo函数中的,但是因为加了个特判,所有写在主函数里
    if (K) topo (); cout << ans << endl;
    return 0;
}

最后,安利一波这个画图网站,真的超级好!