Fibonacci Tree HDU - 4786 (生成树)

版权声明:欢迎大家指正错误,有不同观点的欢迎评论,共同进步 https://blog.csdn.net/Sirius_han/article/details/82453600

Fibonacci Tree

 题目链接:HDU - 4786

题意:给出一个图,每条边的权值要么是0,要么是1,问能否构成一棵生成树,使得这棵树的边权和为斐波那契数;

思路:记图的最大生成树和最小生成树的边权和分别为max, min,那么,一定可以构造出合法的生成树,使得其边权和在区间[min, max];这是个值得思考的地方;

当我们得到一个最小生成树后,想要向最大生成树转换时,必定是通过换边解决,而图中的边权为1 or  0,所以有四种情况:1->1, 1->0, 0->1, 0->0;这四种情况对于边权和的贡献分别为0, -1, 1, 0;所以由min->max的过程中每一个值都必定有对应的生成树结构出现;

所以只需判断区间[min, max]之间有没有斐波那契数就可以了,注意还要判断图是否连通;

#include <bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
int N, M;
int pre[maxn];
int find(int x){
	return x==pre[x]?pre[x]:pre[x]=find(pre[x]);
}
bool Union(int x, int y){
	int fx=find(x), fy=find(y);
	if(fx==fy) return false;
	pre[fx]=fy;
	return true;
}
struct node{
	int u, v, w;
}edge[maxn];
void init(){
	for(int i=0; i<=N; i++){
		pre[i]=i;
	}
}
bool cmp1(node a, node b){
	return a.w<b.w;
}
bool cmp2(node a, node b){
	return a.w>b.w;
}
int Kruskal(){
	init();
	int ret=0, cnt=0;
	for(int i=0; i<M; i++){
		if(Union(edge[i].u, edge[i].v)){
			ret+=edge[i].w;
			cnt++;
		}
		if(cnt==N-1) break;
	}
	if(cnt<N-1) return 0;
	return ret;
}
bool fib[maxn];
void get_fib(){
	memset(fib, false, sizeof(fib));
	fib[0]=false;
	fib[1]=true;
	fib[2]=true;
	int cnt=3, f1=1, f2=2;
	while(1){
		int t=f1+f2;
		f1=f2, f2=t;
		if(t>=maxn) break;
		fib[t]=true;
	}
}
int main(){
	int T, cas=0;
	scanf("%d", &T);
	get_fib();
	while(T--){
		scanf("%d%d", &N, &M);
		for(int i=0; i<M; i++){
			scanf("%d%d%d", &edge[i].u, &edge[i].v, &edge[i].w);
		}
		sort(edge, edge+M, cmp1);
		int minn=Kruskal();
		sort(edge, edge+M, cmp2);
		int maxn=Kruskal();
		int flag=0;
		for(int i=minn; i<=maxn; i++){
			if(fib[i]){
				flag=1;
				break;
			}
		}
		printf("Case #%d: ", ++cas);
		if(flag) printf("Yes\n");
		else printf("No\n");
	}
	return 0;
} 

猜你喜欢

转载自blog.csdn.net/Sirius_han/article/details/82453600
今日推荐