1. 程式人生 > >Fibonacci Tree HDU - 4786 (生成樹)

Fibonacci Tree HDU - 4786 (生成樹)

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;
}