Fibonacci Tree
Description
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
题意:有一个图,有n个点,这m个点有m条边连着,每条边不是白色的就是黑色的,问能否找到一颗生成树,这棵树中白色的边刚好是斐波那契数。
分析:其实就是一个最小生成树的题,做两次最小生成树,第一次按白边为优先级,得到白边的最大值,第二次黑边为优先级,得到白边的最小值,最后只要判断最小值和最大值之间有没有斐波那契数就行了。
代码:
#include<iostream>
#include<string>
#include<cstdio>
#include<cstring>
#include<vector>
#include<math.h>
#include<map>
#include<queue>
#include<algorithm>
using namespace std;
const int inf = 0x3f3f3f3f;
int n,m;
struct node {//定义结构体,表示连接的边和边的颜色,1为白色,0为黑色
int x,y,col;
};
node a[100005];
int fa[100005];
int fb[1000];
int flag[100005];
void init(){//初始化
memset(flag,0,sizeof (flag));
for (int i=1;i<=n;i++){
fa[i]=i;
}
}
bool cmp1(node a,node b){//黑色为优先级
return a.col<b.col;
}
bool cmp2(node a,node b){//白色为优先级
return a.col>b.col;
}
int Find(int x){
return fa[x]==x?x:fa[x]=Find(fa[x]);
}
int main ()
{
int t;
fb[0]=1;
fb[1]=2;
int count;
for (int i=2;;i++){
fb[i]=fb[i-1]+fb[i-2];
if (fb[i]>100000){
count=i;
break;
}
}
scanf ("%d",&t);
int cnt=1;
while (t--){
scanf ("%d%d",&n,&m);
init();//先初始化
for (int i=0;i<m;i++){
scanf ("%d%d%d",&a[i].x,&a[i].y,&a[i].col);
}
if (n-1>m){//如果边数小于n-1,直接输出no
printf ("Case #%d: No\n",cnt++);
continue;
}
sort(a,a+m,cmp1);//按黑色优先级排序,得到白色边的最小值
int sum=1;
int white1=0;
for (int i=0;i<m;i++){
int fu=Find(a[i].x);
int fv=Find(a[i].y);
if (fu!=fv){
sum++;
if (a[i].col){
white1++;
}
if (!flag[a[i].x]){
flag[a[i].x]=1;
}
if (!flag[a[i].y]){
flag[a[i].y]=1;
}
fa[fu]=fv;
}
if (sum==n)break;
}
int tree_num=0;
int judge=0;
for (int i=1;i<=n;i++){//判断能否生成一棵树
if (fa[i]==i) tree_num++;
if (tree_num>1){
judge=1;
break;
}
}
if (judge){//如果不行直接输出no
printf ("Case #%d: No\n",cnt++);
continue;
}
init();//求白边的最大值,初始化
int white2=0;
sum=1;
sort(a,a+m,cmp2);
for (int i=0;i<m;i++){
int fu=Find(a[i].x);
int fv=Find(a[i].y);
if (fu!=fv){
sum++;
if (a[i].col){
white2++;
}
fa[fu]=fv;
}
if (sum==n)break;
}
tree_num=0;
for (int i=1;i<=n;i++){
if (fa[i]==i) tree_num++;
if (tree_num>1){
judge=1;
break;
}
}
if (judge){//判断是否是一棵树
printf ("Case #%d: No\n",cnt++);
continue;
}
//判断是含有斐波那契数,用二分法
int place=lower_bound(fb,fb+count,white1)-fb;
if (fb[place]>=white1&&fb[place]<=white2){
printf ("Case #%d: Yes\n",cnt++);
}
else printf ("Case #%d: No\n",cnt++);
}
return 0;
}