Atcoder传送门
洛谷传送门
题目翻译
有一棵
n
n
n个结点的树,边权均为
1
1
1。
选择
k
k
k个结点
{
x
1
,
x
2
,
.
.
.
,
x
k
}
\{x_1,x_2, ..., x_k\}
{x1,x2,...,xk}。
每个结点
p
p
p可以表示为一个
k
k
k维向量
{
d
i
s
t
(
p
,
x
1
)
,
d
i
s
t
(
p
,
x
2
)
,
.
.
.
,
d
i
s
t
(
p
,
x
k
)
}
\{dist(p, x_1), dist(p, x_2), ..., dist(p, x_k)\}
{dist(p,x1),dist(p,x2),...,dist(p,xk)}。
最小化
k
k
k,使得每个
k
k
k维向量互不相同。
2
≤
n
≤
1
0
5
2 \le n \le 10^5
2≤n≤105
输入输出格式
输入格式
第一行一个正整数 n n n。
以下 n − 1 n-1 n−1行, 每行两个整数 a i , b i a_i,b_i ai,bi, 表示编号为 a i a_i ai和 b i b_i bi的节点之间有一条边。
输出格式
一行一个整数, 表示 k k k最小为多少。
输入输出样例
输入样例#1:
5
0 1
0 2
0 3
3 4
输出样例#1:
2
输入样例#2:
2
0 1
输出样例#2:
1
输入样例#3:
10
2 8
6 0
4 1
7 6
2 3
8 6
6 9
2 4
5 8
输出样例#3:
3
输入样例#4:
5
0 1
0 2
0 3
3 4
输出样例#4:
2
输入样例#5:
2
0 1
输出样例#5:
1
输入样例#6:
10
2 8
6 0
4 1
7 6
2 3
8 6
6 9
2 4
5 8
输出样例#6:
3
解题分析
可以发现, 如果两个点的距离为奇数, 那么显然是可以区分开的。
如果为偶数, 那么设这两个点为 a , b a,b a,b, 中点为 c c c, 显然必须要存在一个 x i x_i xi, 满足当以 c c c为根的时候, x i x_i xi和 a a a或 b b b在同一棵子树里。
换句话说, 以任何一个点作为根的时候,都至多有一棵子树内部没有 x i x_i xi。
我们一遍 D F S DFS DFS就可以完成这个操作, 但要注意的是, 我们要考虑父节点方向是否有 x i x_i xi, 这就很麻烦了。
于是我们从一个度数 ≥ 3 \ge 3 ≥3的节点开始 D F S DFS DFS, 也就保证了父节点方向一定有 x i x_i xi。
代码如下:
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <cctype>
#include <vector>
#include <cstdlib>
#define R register
#define IN inline
#define W while
#define gc getchar()
#define MX 100500
template <class T>
IN void in(T &x)
{
x = 0; R char c = gc;
for (; !isdigit(c); c = gc);
for (; isdigit(c); c = gc)
x = (x << 1) + (x << 3) + c - 48;
}
int n;
std::vector <int> nex[MX];
IN void add(R int from, R int to) {nex[to].push_back(from);}
int dp[MX];
void DFS(R int now, R int fa)
{
bool fir = false;
for (auto i : nex[now])
{
if (i == fa) continue;
DFS(i, now);
dp[now] += dp[i];
if (!dp[i]) fir ? dp[now]++ : fir = true;
}
}
int main(void)
{
in(n); int foo, bar, rt = -1;
for (R int i = 1; i < n; ++i)
in(foo), in(bar), add(foo, bar), add(bar, foo);
for (R int i = 0; i < n; ++i) if (nex[i].size() > 2) {rt = i; break;}
if (~rt) DFS(rt, -1), printf("%d", dp[rt]);
else puts("1");
}