http://acm.hdu.edu.cn/showproblem.php?pid=6228
然后相同颜色的点 用最少的边连起来一条线
那么最后就会有k条线
问这些线 重叠的线段 最多是多少
随便染色,任意点,想了一下好像并没有什么贪心的策略
所以说我们换一个思路考虑。我们知道,在一棵树中,边是与点紧密连接的,而一条边要么属于最后答案所在的集合,要么不属于,那么我们要做的就是看看哪些边可以属于最后答案,哪些不属于。那么我们如何判定呢?我们从答案出发,答案的交集中的边的左右两端一定都包含M种颜色,不然肯定不是交集中的边。所以以此为判据,对于一条边,如果这条边的左右端的点数量都大于颜色的总数量,那么就说明这条边最后可以在最后结果中。统计满足条件的边数即可 --------------------- 本文来自 alpc_qleonardo 的CSDN 博客 ,全文地址请点击:https://blog.csdn.net/u013534123/article/details/78509941?utm_source=copy
#include<bits/stdc++.h>
#define N 201000
#define LL long long
using namespace std;
vector<int> g[N];
int n, m, sz[N];
void getsize(int x, int fa)
//注意第一次fa是0 所以第一个点会发散 从而把所有点跑完
{
//自己算一个
sz[x] = 1;
for (int i = 0; i<g[x].size(); i++)
{
//y是要去地方
int y = g[x][i];
//如果去的地方就是刚刚来的 跳过
if (y == fa) continue;
getsize(y, x);
//回来后加上递归的那些
sz[x] += sz[y];
}
}
int main()
{
int T_T;
cin >> T_T;
while (T_T--)
{
scanf("%d%d", &n, &m);
memset(g, 0, sizeof(g));
for (int i = 1; i<n; i++)
{
int u, v;
scanf("%d%d", &u, &v);
g[u].push_back(v);
g[v].push_back(u);
}
int ans = 0;
//因为编号从1开始 0是不存在的
getsize(1, 0);
//扫点
for (int i = 1; i <= n; i++)
//知道一边 另外一边的点不就是n-sz【i】吗
if (sz[i] >= m&&n - sz[i] >= m) ans++;
printf("%d\n", ans);
}
}