题目大意:
给你一张无向图,其中有的边为白色有的边为黑色,问你是否有一颗生成树并且它的白色边是斐波那契数列中的一个数
思路:
求出白边最少和最多的生成树之后看是否有一个斐波那契数在这之间就可以
代码
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<vector>
#include<cstring>
using namespace std;
int T;
struct edge{
int u,v,c;
int weight;
};
vector<edge> v1,v2;
const int MAX_N = 100005;
int par[MAX_N*3];
int r[MAX_N*3];
class union_find{
public:
void inital(){
for(int i=0;i<3*MAX_N;i++){
par[i] = i;
r[i]= 0;
}
}
int Find(int x){
if(par[x]==x)return x;
else{
return par[x] = Find(par[x]);
}
}
void Union(int x,int y){
x = Find(x);
y = Find(y);
if(x==y)return;
if(r[x]<r[y]){
par[x] = y;
}else{
par[y] = x;
if(r[x]==r[y])r[x]++;
}
}
bool same(int x,int y){
return Find(x)==Find(y);
}
};
bool cmp(edge a,edge b){
return a.weight<b.weight;
}
int spaning_tree(vector<edge> v){
union_find l;l.inital();
sort(v.begin(),v.end(),cmp);
int weight = 0;
for(int i=0;i<v.size();i++){
edge now = v[i];
if(l.same(now.u,now.v))continue;
if(now.c==1)weight++;
l.Union(now.u,now.v);
}
return weight;
}
int st[100005];
int n,m;
union_find lt;
bool ok(){
for(int i=2;i<=n;i++){
if(!lt.same(1,i))return false;
}
return true;
}
int main(){
scanf("%d",&T);
for(int ca=1;ca<=T;ca++){
v1.clear();v2.clear();
memset(st,0,sizeof(st));
lt.inital();
scanf("%d%d",&n,&m);
for(int i=0;i<m;i++){
edge t;
scanf("%d%d%d",&t.u,&t.v,&t.c);
lt.Union(t.u,t.v);
if(t.c==1)t.weight = 1;
else t.weight = 0;
v1.push_back(t);
if(t.c==0)t.weight = 1;
else t.weight = 0;
v2.push_back(t);
}
printf("Case #%d: ",ca);
if(!ok()){printf("No\n");continue;}
int l = spaning_tree(v1);
int r = spaning_tree(v2);
st[0] = 1;st[1] = 2;
if((l<=st[0]&&st[0]<=r)||(l<=st[1]&&st[1]<=r)){
printf("Yes\n");continue;
}
for(int i=2;;i++){
st[i] = st[i-1]+st[i-2];
if(st[i]>r){printf("No\n");break;}
if(st[i]>=l&&st[i]<=r){printf("Yes\n");break;}
}
}
}