Problem 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 <= 105) and M(0 <= M <= 105).
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
题解
这道题的题意就是说我们用白色和黑色的边搭起一颗生成树,有无办法让白色的边的边数是斐波那契数。因为我们不知道到底有几条白边,所以我们希望找到这个白边边数的上下界,枚举他的范围,再打一个表记录数据范围以内的斐波那契数,到时候对着表判定就行了。那么怎么去找这个上下界呢?我们也用Kruskal(贪心)的思路,优先选择白边或黑边(排序的时候改一改cmp)就行了。
代码如下:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=1e5;
int head[N+5],num;
int T;
int n,m;
bool fib[N+5];
int father[N+5];
struct edge
{
int u,v,w,c;
int next;
edge(){next=-1;}
}ed[N*2+5];
void build(int u,int v,int c)
{
ed[++num].u=u;
ed[num].v=v;
ed[num].c=c;
ed[num].next=head[u];
head[u]=num;
}
void fi()//打表打出斐波那契数
{
memset(fib,false,sizeof(fib));
int i=1,j=2,k=0;
fib[1]=fib[2]=true;
while(k<N)
{
k=i+j;
fib[k]=true;
i=j,j=k;
}
}
bool cmp1(edge a,edge b)
{
return a.c<b.c;
}
bool cmp2(edge a,edge b)
{
return a.c>b.c;
}
int getfather(int x)
{
return (father[x]==x)?x:(father[x]=getfather(father[x]));
}
int merge(int x,int y)
{
return ((x=getfather(x))!=(y=getfather(y)))&&(father[x]=y);
}
int kruskal1()//优先选择黑边,白边最少
{
int totw=0,tot=0;
for(int i=1;i<=n;i++)
father[i]=i;
sort(ed+1,ed+1+num,cmp1);
for(int i=1;i<=num;i++)
{
int u=getfather(ed[i].u);
int v=getfather(ed[i].v);
if(u!=v)
{
if(ed[i].c)totw++;
merge(u,v);
tot++;
}
if(tot==n-1)return totw;
}
return -1;
}
int kruskal2()//优先选择白边,白边最多
{
int totw=0,tot=0;
for(int i=1;i<=n;i++)
father[i]=i;
sort(ed+1,ed+1+num,cmp2);
for(int i=1;i<=num;i++)
{
int u=getfather(ed[i].u);
int v=getfather(ed[i].v);
if(u!=v)
{
if(ed[i].c)totw++;
merge(u,v);
tot++;
}
if(tot==n-1)return totw;
}
return -1;
}
int main()
{
fi();
scanf("%d",&T);
for(int k=1;k<=T;k++)
{
memset(head,-1,sizeof(head));
num=0;
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
int u,v,c;
scanf("%d%d%d",&u,&v,&c);
build(u,v,c);
build(v,u,c);
}
int lf=kruskal1(),rg=kruskal2();
if(lf==-1)//lf和rg都可以
{
printf("Case #%d: No\n",k);
continue;
}
int flag=0;
for(int i=lf;i<=rg;i++)
{
if(fib[i])
{
flag=1;
break;
}
}
if(flag)printf("Case #%d: Yes\n",k);
else printf("Case #%d: No\n",k);
}
return 0;
}