【AtCoder Petrozavodsk Contest 001 E - Antennas on Tree】【贪心】

题意

有一棵 n n n 个点的树,现在要在树上放 k k k 个信号站,每个点 x x x 可以用一个 k k k 维向量表示,向量第 i i i 维表示 x x x 与第 i i i 个信号站的距离。求最小的 k k k,使得每个点的向量两两不同。
n ≤ 1 0 5 n\le 10^5 n105

分析

注意到每个点连接的连通块中,至多有 1 1 1 个不包含任何信号站。反过来,若满足上述条件,则所有点都能被区分。

容易得到一个 O ( n 2 ) O(n^2) O(n2) 的做法:枚举根,强制根一定要放信号站。然后递归进行贪心,若超过 1 1 1 棵子树不包含信号站,则在其中 s − 1 s-1 s1 棵中分别放一个信号站即可,其中 s s s 表示不包含信号站的子树数量。

发现若选定一个度数至少为 3 3 3 的点为根,则每个点的父亲所在的连通块中必然会包含信号站。然后套用上面的做法即可。时间复杂度 O ( n ) O(n) O(n)

代码

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

const int N = 100005;

int n, ans;
bool f[N];
vector<int> e[N];

void dfs(int x, int fa)
{
	int s = 0;
	for (int to : e[x]) if (to != fa)
	{
		dfs(to, x);
		s += !f[to];
		f[x] |= f[to];
	}
	if (s > 1) f[x] = 1, ans += s - 1;
}

int main()
{
	scanf("%d", &n);
	for (int i = 1; i < n; i++)
	{
		int x, y; scanf("%d%d", &x, &y);
		x++; y++;
		e[x].push_back(y); e[y].push_back(x);
	}
	int rt = 0;
	for (int i = 1; i <= n; i++) if (e[i].size() > 2) {rt = i; break;}
	if (!rt) {printf("%d\n", 1); return 0;}
	dfs(rt, 0);
	printf("%d\n", ans);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值