Hduoj4786【最小生成树】

#include<stdio.h>
#include<stdlib.h>
struct point
{
	int x, y, o;
}P[100010] ;
int f[100010], F[33];
void get_Fib()
{
	F[1] = 1;
	F[2] = 2;
	for(int i = 3; F[i] <= 30; ++i)
	F[i] = F[i-1] + F[i-2];
}
int find(int x)
{
	if(x != f[x])
	f[x] = find(f[x]);
	return f[x];
}
int merge(int x, int y)
{
	x = find(x);
	y = find(y);
	if(x != y)
	{
		f[x] = y;
		return 1;
	}
	return 0;
}
int cmp(const void *a, const void *b)
{
	return (*(struct point*)a).o - (*(struct point*)b).o;
} 
int main()
{
	int i, j, k, t, n, m, cas = 1;
	scanf("%d", &t);
	get_Fib();
	while(t--)
	{
		scanf("%d%d", &n, &m);
		for(i = 0; i < m; ++i)
		scanf("%d%d%d", &P[i].x, &P[i].y, &P[i].o);
		printf("Case #%d: ", cas++);
		qsort(P, m, sizeof(P[0]), cmp);
		int min = 0, max = 0;
		for(i = 1; i <= n; ++i)
		f[i] = i;
		k = 0;
		for(i = 0; i < m; ++i)
		{
			if(merge(P[i].x, P[i].y))
			{
				k++;
				if(P[i].o == 1)
				min++;
			}
		}
		if(k < n-1)
		{
			printf("No\n");
			continue;
		}
		for(i = 1; i <= n; ++i)
		f[i] = i;
		for(i = m-1; i >= 0; --i)
		{
			if(merge(P[i].x, P[i].y))
			{
				if(P[i].o == 1)
				max++;
			}
		}
		for(i = 1; ; ++i)
		{
			if(F[i] >= min && F[i] <= max)
			{
				printf("Yes\n");
				break;
			}
			if(F[i] > max)
			{
				printf("No\n");
				break;
			}
		}
	}
	return 0;
}


题意:给出n个点和m条边,每条边都有颜色,要么是黑色要么是白色,现在求将这n个点连接在一起所构成的边中,白边的个数是否可以为 Fib数。

思路:由于生成树中可以以一条白边替换成黑边构成一个新的生成树,所以我们只要算出白边的最大数和最小数,便可知道白边的个数是否可能为Fib数了。所以我们将边分成2堆,并且分别由白边和黑边入手,求出白边的最大数和最小数,再枚举Fib数即可。

你可能感兴趣的:(Hduoj4786【最小生成树】)