Luogu P5536

听说 blog 食用更佳

核心思想 : topo


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

Luogu P5536

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

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

那么来看看下面这个图:
Luogu P5536

先设它的根为 1 号节点。

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

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

Luogu P5536

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

Luogu P5536

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

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

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

是不是感觉和 topo 想法很像。


上代码!!!

# 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;
			//这一句不能落掉,是 topo 函数的关键
			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;
}

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

Made By \(\operatorname{wheneveright}\)

上一篇:《php和mysql web开发》 学习笔记


下一篇:JZOJ 5382. 数列