HDU - 4786 Fibonacci Tree (Kruskal)

版权声明:本文为博主原创文章,转载请附上注明就行_(:з」∠)_。 https://blog.csdn.net/vocaloid01/article/details/82460445

 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

题解:用Kruskal方法求两遍生成树, 一遍优先用黑边,一遍优先用白边,得到用白边的最小数量mi和最大数量ma,那么只要

[mi,ma]中有Fibonacci 数就肯定能实现。

代码:

#include <cstdio>
#include <cstring>
#include <queue>

using namespace std;
 
const int MAXN = 100005;
 
int N,M;//点数;边数。 
 
int pre[MAXN];//记录点的祖先 
int Fi[MAXN];
 
struct Edge{//边结构体 
	int from;
	int to;
	int value;
	Edge(){}
	Edge(int a,int b,int c):from(a),to(b),value(c){}
};
 
struct cmp1{
	bool operator()(struct Edge a,struct Edge b){
		return a.value > b.value;
	}
};

struct cmp2{
	bool operator()(struct Edge a,struct Edge b){
		return a.value < b.value;
	}
};
 
priority_queue<struct Edge,vector<struct Edge>,cmp1> Q1;
priority_queue<struct Edge,vector<struct Edge>,cmp2> Q2;
 
int Find(int a){
	if(pre[a] == a)return a;
	return pre[a] = Find(pre[a]);
}
 
bool Judge(int a,int b){
	int A = Find(a);
	int B = Find(b);
	if(A != B){
		pre[A] = B;
		return true;
	}
	return false;
}
 
int Num;//表示已经找到的边数;表示最小生成树的值。 
 
inline void init(){
	while(!Q1.empty())Q1.pop(); //清空优先队列
	while(!Q2.empty())Q2.pop(); 
	Num = 0;
	for(int i=0 ; i<=N ; ++i)pre[i] = i;//初始化祖先为自己。
}
 
int main(){
	
	Fi[1] = 1;
	Fi[2] = 2;
	for(int i=3 ; Fi[i-1]<100005 ; ++i){
		Fi[i] = Fi[i-1] + Fi[i-2];
	}
	
	int T,a,b,c;
	scanf("%d",&T);
	for(int _=1 ; _<=T ; ++_){
		scanf("%d %d",&N,&M);
		init();
		for(int i=1 ; i<=M ; ++i){
			scanf("%d %d %d",&a,&b,&c);
			Q1.push(Edge(a,b,c));
			Q2.push(Edge(a,b,c));
		}
		int mi = 0,ma = 0;
		while(!Q1.empty() && Num<N-1){//找N-1条边就够了。 
			if(Judge(Q1.top().from,Q1.top().to)){
				mi += Q1.top().value;
				++Num;
			}
			Q1.pop();
		}
		if(Num < N-1){//判断是否联通 
			printf("Case #%d: No\n",_);
			continue;
		}
		Num = 0;
		for(int i=0 ; i<=N ; ++i)pre[i] = i;
		while(!Q2.empty() && Num<N-1){
			if(Judge(Q2.top().from,Q2.top().to)){
				ma += Q2.top().value;
				++Num;
			}
			Q2.pop();
		}
		printf("Case #%d: ",_);
		for(int i=1 ; i<MAXN ; ++i){
			if(Fi[i]>=mi && Fi[i]<=ma){
				printf("Yes\n");
				break;
			}
			else if(Fi[i] > ma){
				printf("No\n");
				break;
			}
		}
	}
	
	return 0;
}

猜你喜欢

转载自blog.csdn.net/vocaloid01/article/details/82460445
今日推荐