思维题 n个点的树 染k种颜色

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);

	}

}

猜你喜欢

转载自blog.csdn.net/liangnimahanwei/article/details/82870529