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
题解:用Kruskal方法求两遍生成树, 一遍优先用黑边,一遍优先用白边,得到用白边的最小数量mi和最大数量ma,那么只要
[mi,ma]中有Fibonacci 数就肯定能实现。
代码:
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
const int MAXN = 100005;
int N,M;//点数;边数。
int pre[MAXN];//记录点的祖先
int Fi[MAXN];
struct Edge{//边结构体
int from;
int to;
int value;
Edge(){}
Edge(int a,int b,int c):from(a),to(b),value(c){}
};
struct cmp1{
bool operator()(struct Edge a,struct Edge b){
return a.value > b.value;
}
};
struct cmp2{
bool operator()(struct Edge a,struct Edge b){
return a.value < b.value;
}
};
priority_queue<struct Edge,vector<struct Edge>,cmp1> Q1;
priority_queue<struct Edge,vector<struct Edge>,cmp2> Q2;
int Find(int a){
if(pre[a] == a)return a;
return pre[a] = Find(pre[a]);
}
bool Judge(int a,int b){
int A = Find(a);
int B = Find(b);
if(A != B){
pre[A] = B;
return true;
}
return false;
}
int Num;//表示已经找到的边数;表示最小生成树的值。
inline void init(){
while(!Q1.empty())Q1.pop(); //清空优先队列
while(!Q2.empty())Q2.pop();
Num = 0;
for(int i=0 ; i<=N ; ++i)pre[i] = i;//初始化祖先为自己。
}
int main(){
Fi[1] = 1;
Fi[2] = 2;
for(int i=3 ; Fi[i-1]<100005 ; ++i){
Fi[i] = Fi[i-1] + Fi[i-2];
}
int T,a,b,c;
scanf("%d",&T);
for(int _=1 ; _<=T ; ++_){
scanf("%d %d",&N,&M);
init();
for(int i=1 ; i<=M ; ++i){
scanf("%d %d %d",&a,&b,&c);
Q1.push(Edge(a,b,c));
Q2.push(Edge(a,b,c));
}
int mi = 0,ma = 0;
while(!Q1.empty() && Num<N-1){//找N-1条边就够了。
if(Judge(Q1.top().from,Q1.top().to)){
mi += Q1.top().value;
++Num;
}
Q1.pop();
}
if(Num < N-1){//判断是否联通
printf("Case #%d: No\n",_);
continue;
}
Num = 0;
for(int i=0 ; i<=N ; ++i)pre[i] = i;
while(!Q2.empty() && Num<N-1){
if(Judge(Q2.top().from,Q2.top().to)){
ma += Q2.top().value;
++Num;
}
Q2.pop();
}
printf("Case #%d: ",_);
for(int i=1 ; i<MAXN ; ++i){
if(Fi[i]>=mi && Fi[i]<=ma){
printf("Yes\n");
break;
}
else if(Fi[i] > ma){
printf("No\n");
break;
}
}
}
return 0;
}