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, ... )
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).
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
题意:给你一个图,图中边颜色为白色(1表示)或者黑色(0表示),问你是否能找出一棵树,使这棵树中白边的总数量的值为Fib数。点数n和变数m均为不大于1e5的数。
分析:这是最小生成树的变形题,用Kruskal求解,我们可以通过求两次最小生成树得到白边数量的上下限,再判断这个区间内有没有fib数即可,第一次我们以黑边为主排序求最小生成树,得到白边数量下限,再以白边为主排序求最小生成树得到白边数量上限。注意如果一开始图不连通,那么输出No。
#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
int f[1000010];
struct node
{
int u,v,c;
}E[200010];
int fin[200010];
int find(int x)
{
if(f[x] == -1)return x;
return f[x] = find(f[x]);
}
bool cmp1(node a,node b)
{
return a.c < b.c;
}
bool cmp2(node a,node b)
{
return a.c > b.c;
}
int main()
{
int num = 1;
fin[0] = 1;
fin[1] = 2;
while(fin[num] <= 1000010)
{
fin[num+1] = fin[num] + fin[num-1];
num++;
}//预处理fib数列
int T;
int count = 0;
int n,m;
scanf("%d",&T);
while(T--)
{
count++;
scanf("%d%d",&n,&m);
for(int i = 0;i < m;i++)
scanf("%d%d%d",&E[i].u,&E[i].v,&E[i].c);
sort(E,E+m,cmp1);
memset(f,-1,sizeof(f));
int cnt = 0;
for(int i = 0;i < m;i++)
{
int t1 = find(E[i].u);
int t2 = find(E[i].v);
if(t1 != t2)
{
f[t1] = t2;
if(E[i].c == 1)cnt++;
}
}
int Low = cnt;
memset(f,-1,sizeof(f));
sort(E,E+m,cmp2);
cnt = 0;
for(int i = 0;i < m;i++)
{
int t1 = find(E[i].u);
int t2 = find(E[i].v);
if(t1 != t2)
{
f[t1] = t2;
if(E[i].c == 1)cnt++;
}
}
int High = cnt;
bool ff = true;
for(int i = 1;i <= n;i++)
if(find(i) != find(1))
{
ff = false;
break;
}//判断图是否连通
if(!ff)
{
printf("Case #%d: No\n",count);
continue;
}
bool flag = false;
for(int i = 0;i <= num;i++)
if(fin[i] >= Low && fin[i] <= High)
flag = true;
if(flag)
printf("Case #%d: Yes\n",count);
else printf("Case #%d: No\n",count);
}
return 0;
}