首页 > 代码库 > HDU 4786 Fibonacci Tree 生成树

HDU 4786 Fibonacci Tree 生成树

链接:http://acm.hdu.edu.cn/showproblem.php?pid=4786

题意:有N个节点(1 <= N <= 10^5),M条边(0 <= M <= 10^5),其中一部分边被染成了黑色,剩下的边是白色,问能不能建立一棵树,树中有斐波那契数个白色边。

思路:用克鲁斯卡尔建三次树,第一是用所有边建树,判断是否能建成一棵树,第二次用黑边建树,最多可以用到x条黑边(不成环),n-1-x就是最少需要用的白边的数量,第三次用白边建树,最多可以用到y条白边。如果在【y,n-1-x】中有斐波那契数,则可以满足题意来建立这棵树。

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <map>
#include <cstdlib>
#include <queue>
#include <stack>
#include <vector>
#include <ctype.h>
#include <algorithm>
#include <string>
#include <set>
#define PI acos(-1.0)
#define maxn 10005
#define INF 0x7fffffff
#define eps 1e-8
typedef long long LL;
typedef unsigned long long ULL;
using namespace std;
int root[100005];
int findset(int x)
{
    return x==root[x]?x:root[x]=findset(root[x]);
}
int Fib[40];
void init()
{
    Fib[0]=1;
    Fib[1]=1;
    for(int i=2; i<=29; i++)
        Fib[i]=Fib[i-1]+Fib[i-2];
}
struct edge
{
    int x,y;
    int color;
} e[100005];
int Kruskal_w(edge e[],int m,int n,int f)
{
    int sum=0;
    for(int i=0; i<m; i++)
        if(sum>=n-1)
            break;
        else if(e[i].color==f)
        {
            int xx=findset(e[i].x);
            int yy=findset(e[i].y);
            if(xx==yy)
                continue;
            else
            {
                if(xx<yy)
                    root[yy]=xx;
                else root[xx]=yy;
                sum++;
            }
        }
    return sum;
}
int Kruskal_a(edge e[],int m,int n,int &sum1)
{
    int sum=0;
    for(int i=0; i<m; i++)
    {
        if(sum1>=n-1)
            break;
        else if(e[i].color==1)
        {
            int xx=findset(e[i].x);
            int yy=findset(e[i].y);
            if(xx==yy)
                continue;
            else
            {

                if(xx<yy)
                    root[yy]=xx;
                else root[xx]=yy;
                sum++;
                sum1++;
            }
        }
        else
        {
            int xx=findset(e[i].x);
            int yy=findset(e[i].y);
            if(xx==yy)
                continue;
            else
            {
                sum1++;
                if(xx<yy)
                    root[yy]=xx;
                else root[xx]=yy;
            }
        }
    }
    return sum;
}
int main()
{
    int T;
    scanf("%d",&T);
    init();
    for(int ii=1;ii<=T;ii++)
    {
        int n,m;
        scanf("%d%d",&n,&m);
        for(int i=0; i<m; i++)
        {
            scanf("%d%d",&e[i].x,&e[i].y);
            scanf("%d",&e[i].color);
        }
        for(int i=0;i<=n;i++)
            root[i]=i;
        int sum1=Kruskal_w(e,m,n,1);
        int sum2=0;
        for(int i=0;i<=n;i++)
            root[i]=i;
        int sum3=Kruskal_a(e,m,n,sum2);
        for(int i=0;i<=n;i++)
            root[i]=i;
        int sum4=Kruskal_w(e,m,n,0);
        printf("Case #%d: ",ii);
        bool flag=0;
        if(sum2==n-1)
        {
            for(int i=0; i<=29; i++)
            {
                if(Fib[i]>=n-1-sum4&&Fib[i]<=sum1)
                {
                    flag=1;
                    break;
                }
            }
            if(flag)
                printf("Yes\n");
            else printf("No\n");
        }
        else printf("No\n");
    }
    return 0;
}