HDU - 4786 ——Fibonacci Tree

 Coach Pang is interested in Fibonacci numbers while Uncle Yang wants him to do some research on Spanning Tree. So Coach Pang decides to solve the following problem: 
  Consider a bidirectional graph G with N vertices and M edges. All edges are painted into either white or black. Can we find a Spanning Tree with some positive Fibonacci number of white edges? 
(Fibonacci number is defined as 1, 2, 3, 5, 8, ... )

Input

  The first line of the input contains an integer T, the number of test cases. 
  For each test case, the first line contains two integers N(1 <= N <= 10 5) and M(0 <= M <= 10 5). 
  Then M lines follow, each contains three integers u, v (1 <= u,v <= N, u<> v) and c (0 <= c <= 1), indicating an edge between u and v with a color c (1 for white and 0 for black).

Output

  For each test case, output a line “Case #x: s”. x is the case number and s is either “Yes” or “No” (without quotes) representing the answer to the problem.

Sample Input

2
4 4
1 2 1
2 3 1
3 4 1
1 4 0
5 6
1 2 1
1 3 1
1 4 1
1 5 1
3 5 1
4 2 1

Sample Output

Case #1: Yes
Case #2: No

题意:给你n个点,m个关系,1 表示白边, 0表示黑边,为是否有 k条白边和随便几条黑边构成一颗树,并且k要为斐波那契数;

思路就是黑边不限定数量  但是限制的是白边的数量一定要是斐波那契数  ,并且只有1, 0两种边;

那是不是判断一个最多的白边构成的树,和一个最少白边构成的树,在这期间的白边数一定能构成树;

你想最大生成树也就是最多白边构成的树,那如果我现在减少一条边,是不是后有一个点空出来,那我现在重新构成树,但是现在我不把拿出来的白边算进去,是不是后构成新的树  而那个点会有别的边相连; 树可能不是同一棵树,但是题目树一定能构成树就对了;

 

你这是要特判一下  本来就不是树的情况;

 

ac码

#include <cstdio>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <string>
#include <queue>
#include <vector>
#include <map>

using namespace std;
typedef long long LL;



int fa[100005];
struct po
{
	int u ,v ,w;
}eg[100005];


int n,m;
int fb()  //预处理斐波那契数列
{
	a[0] = 1,a[1] = 2;
	for(int i = 2; ; i++)
	{
		a[i] = a[i - 1] + a[i - 2];
		if(a[i] > 100500)
		{
			return i;
			break;
		}
	}
}

bool cmp1(po x,po y)  
{

	return x.w < y.w;  //xiao到da
}

bool cmp2(po x,po y)
{
	return x.w > y.w;  //da到xiao
}

int find(int x)
{
	if(x!=fa[x])
		fa[x]=find(fa[x]);
	return fa[x];
}

int bpf()    //避圈法
{
	int tot = n;
	int sum = 0;
	for(int i = 0;i < m;i++)
	{
		int x = find(eg[i].u);
		int y = find(eg[i].v);
		if(x == y)
			continue;
		fa[x] = y;
		sum += eg[i].w;
		tot--;      //因为会有重边  其实我感觉不需要也行
		if(tot == 0)break;
	}
	return sum;
}

int main()
{
	int t;
	int fbb = fb(); 
	scanf("%d",&t);
	for(int k = 1;k <= t;k++)
	{
		scanf("%d %d",&n,&m);
		for(int i = 1;i <= m;i++)
		{
			int a,b,c;
			scanf("%d %d %d",&a,&b,&c);
			eg[i].u = a;
			eg[i].v = b;
			eg[i].w = c;
		}
		for(int i = 1;i <= n;i++) fa[i] = i;
		sort(eg + 1,eg + m + 1,cmp2);   
		int r = bpf();     //  最大白边生成树
		for(int i = 1;i <= n;i++) fa[i] = i;
		sort(eg + 1, eg + m + 1 , cmp1);  
		int l = bpf();	 //最小白边生成树

		int ff = 1;
		for(int i = 1;i <= n;i++)   //特判一下是不是n个点一定能构成一棵树
			if(find(i) != find(1))
			{
				ff = 0;
				break;
			}
		if(ff == 0)   //不能构成一棵树
		{
			printf("Case #%d: No\n",k);
			continue;
		}
		int flag = 0;
		for(int i = 1;i < fbb;i++)     //判断期间是否存在斐波那契数
			if(a[i] >= l && a[i] <= r)
				flag = 1;
		if(flag)
			printf("Case #%d: Yes\n",k);
		else
			printf("Case #%d: No\n",k);
	}

	return 0;
}

猜你喜欢

转载自blog.csdn.net/strawberry_595/article/details/81124521