这里主要补一下L题,感觉也是挺巧妙的,不过也不难
题目大意:
给予一个无根树,然后给予K种颜色,求将所有颜色的点都连接起来,这K种颜色最多有多少条公共的边。
解题思路:
- 首先看一个图,我们直接拆分边,如果这个边的两端都有>=k 个点,那么这条边就可以公共通过。
- 假如K == 3, 那么如果我切割中间的边, 那么左右的点的数目都是 >= 3 ,就符合条件,所以我们根据这个性质来继续解题。
- 因此我们只需要找一个点作为根即可。(找度为1的点,比较方便)
- 然后我们记录每个点有多少个子节点,然后我们去遍历每个点,他的子节点 和 n - 子节点 ,判断这两个数值是否 >= k 即可,累加统计
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <unordered_map>
#include <stack>
#include <cmath>
#include <deque>
using namespace std;
typedef long long ll;
const int N = 200010, M = 400010;
const int mod = 1e9 + 7;
pair <int,int> ans[N];
int h[N], e[M], ne[M], idx;
int d[N];
int b[N];
int num = 1;
void add(int x, int y){
e[idx] = y, ne[idx] = h[x], h[x] = idx ++;
}
void dfs(int u, int f){
b[u] = 1;
for (int i = h[u]; i != -1; i = ne[i]){
int j = e[i];
if (j != f){
dfs(j,u);
}
}
if (f != -1) b[f] += b[u];
}
int main(){
int t;
scanf("%d",&t);
while(t--){
idx = 0;
memset(d,0,sizeof d);
memset(h,-1,sizeof h);
int n, k;
scanf("%d%d",&n,&k);
for (int i = 1; i <= n - 1; i ++){
int x, y;
scanf("%d%d",&x,&y);
ans[i] = {x,y};
d[x] ++, d[y] ++;
add(x,y), add(y, x);
}
int res = 0;
int x;
for (int i = 1; i <= n; i++){
if (d[i] == 1){
x = i;
}
}
dfs(x, -1);
for (int i = 1; i <= n; i++){
if (b[i] >= k && n - b[i] >= k) res ++;
}
printf("%d\n",res);
}
return 0;
}