题解 P5536 【XR-3】核心城市
wheneveright · · 题解
P5536 【XR-3】核心城市
解法
看了下好像题解都是写以直径为基础的算法,我来讲一下鄙人自己对于这道题的认识。
如图,这是一颗满足题目要求的无根树
这时,如果
那么来看看下面这个图:
先设它的根为 1 号节点。
让我们看看
那当
你可以这样,此时答案是1且最优。
你也可以这样,此时答案是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;
}
最后,安利一波这个画图网站,真的超级好!