hdu 4786 Fibonacci Tree

        题意:给一个图,有些边是白色的,有些边是黑色的,问有没有这样的生成树使得白边的数量是斐波那契数。

        思路:Kruskal算法。白边排前面和后面各跑一次,算出最多和最少可以有多少条白边,如果夹着斐波那契数,就是可行的。当然,建不出生成树肯定不行。这里给不出证明。。求大牛指教。


#include <iostream>         
#include <stdio.h>         
#include <cmath>         
#include <algorithm>         
#include <iomanip>         
#include <cstdlib>         
#include <string>         
#include <string.h>         
#include <vector>         
#include <queue>         
#include <stack>         
#include <map>       
#include <set>       
#include <ctype.h>         
#include <sstream>     
   
#define ll long long     
#define min3(a,b,c) min(a,min(b,c))  
#define max3(a,b,c) max(a,max(b,c)) 
#include<time.h>
using namespace std;

#define INF 1000000

int p[100010];

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

void _union(int a,int b){
	int fa=find(a);
	int fb=find(b);
	p[fa]=fb;
	find(a);
}

struct edge{
	int u;
	int v;
};

edge E0[100010];
edge E1[100010];
bool vis0[100010];
bool vis1[100010];
int n,m;

void init(){
	memset(vis0,0,sizeof(vis0));
	memset(vis1,0,sizeof(vis1));
	for(int i=1;i<=n;i++)p[i]=i;
}

int main(){
	int t;
	cin>>t;
	int cas=0;
	while(t--){
		cas++;
		cin>>n>>m;
		int cnt0=0;
		int cnt1=0;
		int u,v,w;
		for(int i=1;i<=m;i++){
			scanf("%d%d%d",&u,&v,&w);
			if(w){
				E1[cnt1].u=u;
				E1[cnt1++].v=v;
			}else{
				E0[cnt0].u=u;
				E0[cnt0++].v=v;
			}
		}
		//
		init();
		int _min=0;
		int i=0,j=0;
		bool flag=0;
		for(int q=1;q<n;q++){
			flag=0;
			for(;i<cnt0;i++){
				int u=E0[i].u;
				int v=E0[i].v;
				if(find(u)!=find(v)){
					_union(u,v);
					flag=1;
					break;
				}
			}
			if(flag)continue;
			for(;j<cnt1;j++){
				int u=E1[j].u;
				int v=E1[j].v;
				if(find(u)!=find(v)){
					_union(u,v);
					flag=1;
					_min++;
					break;
				}
			}
			if(!flag)break;
		}
		if(!flag){
			printf("Case #%d: No\n",cas);
			continue;
		}
		//
		init();
		int _max=0;
		i=0,j=0;
		for(int q=1;q<n;q++){
			flag=0;
			for(;j<cnt1;j++){
				int u=E1[j].u;
				int v=E1[j].v;
				if(find(u)!=find(v)){
					_union(u,v);
					flag=1;
					_max++;
					break;
				}
			}
			if(flag)continue;
			for(;i<cnt0;i++){
				int u=E0[i].u;
				int v=E0[i].v;
				if(find(u)!=find(v)){
					_union(u,v);
					flag=1;
					break;
				}
			}
			if(!flag)break;
		}
		
		int a=1;
		int b=1;
		flag=0;
		while(a<=100000){
			int tmp=a;
			a=a+b;
			b=tmp;
			if(_min<=b&&_max>=b)flag=1;
		}
		if(flag){
			printf("Case #%d: Yes\n",cas);
		}else{
			printf("Case #%d: No\n",cas);
		}
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值