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

题目大意:能否找到一个生成树使得他的白边数目为一个斐波那契数.

题目思路:有点思维意思,我们求一遍最大生成树(因为白边为1,那么就是生成树中,白边的最大数量),再求一遍最小生成树(最小白边数量),判断中间是否有斐波那契数即可.原理:对于一个带权图来说,我们考虑如果只有n-1条边,那么最大生成树和最小生成树是一样的,而只要出现>n-1条边,便会出现环,这就使得,链接两个点之间可能有多条路,为什么最小生成树和最大生成树不同?因为两个点之间都选择了最大权值链接(最大生成树),而最小生成树则不然,所以,任何权值的生成树都可以在这两个(max与min)之间选择,还不明白,考虑极端情况,如果最小生成树,凡是有两个点之间有多条路的,都选择最大权值相连这两个点,就成了最大生成树,所以中间的生成树可以通过选择部分改变来生成

代码:

//#include<bits/stdc++.h>
#define ll long long
#include <stdio.h>
#include <algorithm>
#pragma GCC optimize(2)
using namespace std;
const int maxn=1e6+1000;
const int INF=1e9+7;
inline ll read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
ll n,m;
struct node{
    int s,e;
    int f;
}edge[maxn];
int pre[maxn];
int save[1000];
int Find(int x)
{
    return pre[x]==x?x:pre[x]=Find(pre[x]);
}
bool Merge(int x,int y)
{
    int fx=Find(x);
    int fy=Find(y);
    if(fx!=fy)
    {
        pre[fy]=fx;
        return true;
    }
    return false;
}
bool cmp1(node a,node b)
{
    return a.f>b.f;
}
bool cmp2(node a,node b)
{
    return a.f<b.f;
}
int main()
{
    int cnt=0;
    save[++cnt]=1;save[++cnt]=2;
    for(int i=3;i;i++)
    {
        save[++cnt]=save[i-1]+save[i-2]; 
        if(save[i-1]+save[i-2]>100100) break;
    }
    int T;scanf("%d",&T);
    int cas=0;
    while(T--)
    {
        scanf("%lld%lld",&n,&m);
        for(int i=1;i<=m;i++)
            scanf("%d%d%d",&edge[i].s,&edge[i].e,&edge[i].f);
        for(int i=1;i<=n+1;i++) pre[i]=i;
        sort(edge+1,edge+1+m,cmp1);//decreasing
        int ans=0,res=0,res1=0;
        for(int i=1;i<=m&&ans<n-1;i++)
        {
            if(Merge(edge[i].s,edge[i].e))
            {
                ans++;
                res+=edge[i].f;
            }
        }
        if(ans!=n-1)
        {
            printf("Case #%d: No\n",++cas);
            continue;
        }
        for(int i=1;i<=n+1;i++) pre[i]=i;
        sort(edge+1,edge+1+m,cmp2);
        ans=0;
        for(int i=1;i<=m&&ans<n-1;i++)
        {
            if(Merge(edge[i].s,edge[i].e))
            {
                ans++;
                res1+=edge[i].f;
            }
        }
        bool flag=false;
        for(int i=1;i<=cnt;i++)
        {
            if(save[i]>res) break;
            if(save[i]>=res1&&save[i]<=res)
            {
                flag=true;
                break;
            }
        }
        if(flag) printf("Case #%d: Yes\n",++cas);
        else printf("Case #%d: No\n",++cas);
    }
    return 0;
}