Fibonacci Tree
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 3768 Accepted Submission(s): 1191
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, ... )
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).
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
Case #1: Yes Case #2: No
这道题特别郁闷,明明感觉没错的啊,跟别人写的也几乎差不多啊(刚开始是思路差不多,到后米变成代码差不多了),但是依旧有错,最后把别人的代码粘贴过来改成我定义的一些字符,提交就对了,但是提交我自己的与他的几乎一样的代码,还是wrong,不过不想管那么多了。
这个题的意思是给定一些点边,有些边为白色即为1,有些边为黑色即为0,要求所有生成树中,含有白色边的条数是否有Fibonacci数列中的数,如果有则输出yes,否则输出no.也就是求生成树时所用到的白边范围中是否含有Fibonacci数,用kruskal来求得所用白边的数量,先对边进行排序,以黑色为主的升序排序,计算出需要用到白边的最小数量aa,以白色为主的降序排序,计算出需要用到白边的最大数量bb,最后在这个范围内查询是否含有Fibonacci数,最初我的想法是把小于等于100000的Fibonacci数装在一个数组李,只有24个数(第24个已经是大于100000的了),然后用二分的方法来查询比aa大的所有数中最小的那个数,然后与bb比较,如果小于等于则输出yes,否则输出no。但是程序一直错,最后不得不换为这个方法,定义一个长为100000的fib数组,是Fibonacci数的那一位则赋值为true,不是的都是false。
//这个是我用别人的代码改的,是对的
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int fa[110000];
bool fib[110000];
struct node
{
int st,en,co;
}e[110000];
int Find(int x)
{
if(fa[x]==x) return x;
else return fa[x]=Find(fa[x]);
}
bool cmp1(node a,node b)
{
return a.co<b.co;
}
bool cmp2(node a,node b)
{
return a.co>b.co;
}
void Fibonacci() //预处理Fibonacci数组
{
memset(fib,false,sizeof(fib));
int a=1,b=2,c;
fib[a]=fib[b]=true;
while(1)
{
c=a+b;
if(c>100000) break;
fib[c]=true;
a=b,b=c;
}
}
int main()
{
int T;
scanf("%d",&T);
Fibonacci();
for(int k=1;k<=T;k++)
{
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
scanf("%d%d%d",&e[i].st,&e[i].en,&e[i].co);
int ans1=0,ans2=0;
sort(e+1,e+m+1,cmp1); //以黑边为主的排序
for(int i=1;i<=n;i++) fa[i]=i;
for(int i=1;i<=m;i++)
{
int fx=Find(e[i].st),fy=Find(e[i].en);
if(fx!=fy)
{
if(e[i].co) ans1++; //如果是白边则加1
fa[fx]=fy;
}
}
int fg=1,tem=Find(1);
for(int i=2;i<=n;i++)
{
if(Find(i)!=tem)
{
fg=0;
break;
}
}
if(!fg)
{
printf("Case #%d: No\n",k);
continue;
}
sort(e+1,e+m+1,cmp2); //以白边为主的排序
for(int i=1;i<=n;i++) fa[i]=i;
for(int i=1;i<=m;i++)
{
int fx=Find(e[i].st),fy=Find(e[i].en);
if(fx!=fy)
{
if(e[i].co) ans2++;
fa[fx]=fy;
}
}
fg=0;
for(int i=ans1;i<=ans2;i++) //从最小数到最大数依次与fib数组的数相比较
{
if(fib[i])
{
fg=1;
break;
}
}
if(fg) printf("Case #%d: Yes\n",k);
else printf("Case #%d: No\n",k);
}
return 0;
}
//下面的是我自己敲的代码,是错的
#include <iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int fa[110000];
bool fib[110000];
struct node
{
int st,en,len;
}e[110000];
int Find(int x)
{
if(x==fa[x]) return x;
else return fa[x]=Find(fa[x]);
}
bool cmp1(node n1,node n2)
{
return n1.len<n2.len;
}
bool cmp2(node n1,node n2)
{
return n1.len>n2.len;
}
void Fibonacci()
{
memset(fib,false,sizeof(fib));
int a=1,b=2,c;
fib[1]=true;
fib[2]=true;
while(1)
{
c=a+b;
if(c>100000) break;
fib[c]=true;
a=b;
b=c;
}
}
int main()
{
int T;
scanf("%d",&T);
Fibonacci();
for(int k=1;k<=T;k++)
{
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&e[i].st,&e[i].en,&e[i].len);
}
int aa=0,bb=0;
sort(e+1,e+m+1,cmp1);
for(int i=1;i<=n;i++) fa[i]=i;
for(int i=1;i<=m;i++)
{
int x=Find(e[i].st),y=Find(e[i].en);
if(x!=y)
{
if(e[i].len) aa++;
fa[x]=y;
}
}
int flag=1,tem=Find(1);
for(int i=2;i<=n;i++)
{
if(Find(i)!=tem)
{
flag=0;
break;
}
}
if(!flag)
{
printf("Case #%d: NO\n",k);
continue;
}
sort(e+1,e+m+1,cmp2);
for(int i=1;i<=n;i++) fa[i]=i;
for(int i=1;i<=m;i++)
{
int x=Find(e[i].st),y=Find(e[i].en);
if(x!=y)
{
if(e[i].len) bb++;
fa[x]=y;
}
}
flag=0;
for(int i=aa;i<=bb;i++)
{
if(fib[i])
{
flag=1;
break;
}
}
if(flag)
printf("Case #%d: Yes\n",k);
else printf("Case #%d: NO\n",k);
}
return 0;
}