HDU4786 Fibonacci Tree【最小生成树】

题目链接:

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

题目大意:

给你图的N个点和M条双向边。告诉你每条边的权值。权值为1表示该边是白边,权值为0表示该

边为黑边。问:能否找到一棵生成树,使生成树白边的个数恰好为fibonacci数。如果能构成这样

的fibonacci树,输出Yes,否则输出No。

思路:

先将fibonacci数列打表。然后根据题意构图。然后根据边的权值大小排序,用Kruskal先求一遍

最小生成树,再求一遍最大生成树。如果最小生成树和最大生成树之间存在fibonacci树,则说明

能够成fibonacci树。这是因为如果最大生成树不是fibonacci树,则可以将最大生成树的部分白

边替换成黑边(权值减少),从而去凑成fibonacci树。同理,最小生成树也可以通过将部分黑边替

换成白边从而凑成fibonacci树。如果最小生成树和最大生成树之间找不到fibonacci值,说明构成

不了fibonacci树。

AC代码:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;

struct EdgeNode
{
    int u;
    int v;
    int w;
}Edges[200100];

int cmp(EdgeNode a, EdgeNode b)
{
    return a.w < b.w;
}
int Father[100100],Fibo[100100],j,id,N,M;

int Fibonaci()
{
    Fibo[1] = 1;
    Fibo[2] = 2;
    for(int i = 3; Fibo[i] <= 100100; ++i)
    {
        Fibo[i] = Fibo[i-1] + Fibo[i-2];
        if(Fibo[i] >= 100100)
            return i;
    }
}

int Find(int x)
{
    if(x != Father[x])
        Father[x] = Find(Father[x]);
    return Father[x];
}

int Kruskal1()
{
    for(int i = 0; i <= N; ++i)
        Father[i] = i;
    int Num = 0,Sum = 0;
    for(int i = 0; i < id; ++i)
    {
        int u = Find(Edges[i].u);
        int v = Find(Edges[i].v);
        if(u != v)
        {
            Father[u] = v;
            Num++;
            Sum += Edges[i].w;
        }
        if(Num == N-1)
            break;
    }
    if(Num == N-1)
        return Sum;
    else
        return 0;
}

int Kruskal2()
{
    for(int i = 0; i <= N; ++i)
        Father[i] = i;
    int Num = 0,Sum = 0;
    for(int i = id-1; i >= 0; --i)
    {
        int u = Find(Edges[i].u);
        int v = Find(Edges[i].v);
        if(u != v)
        {
            Father[u] = v;
            Num++;
            Sum += Edges[i].w;
        }
        if(Num == N-1)
            break;
    }
    if(Num == N-1)
        return Sum;
    else
        return 0;
}
int main()
{
    int T,kase = 0,u,v,w;
    j = Fibonaci();
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&N,&M);
        id = 0;
        for(int i = 0; i <= N; ++i)
            Father[i] = i;
        for(int i = 0; i < M; ++i)
        {
            scanf("%d%d%d",&u,&v,&w);
            Edges[id].u = u;
            Edges[id].v = v;
            Edges[id++].w = w;
            Edges[id].u = v;
            Edges[id].v = u;
            Edges[id++].w = w;
        }
        sort(Edges, Edges+id, cmp);
        int Num1 = Kruskal1();
        int Num2 = Kruskal2();
        bool flag = 0;
        for(int i = Num1; i <= Num2; ++i)
        {
            if(flag)
                break;
            for(int k = 1; k < j; ++k)
            {
                if(i == Fibo[k])
                {
                    flag = 1;
                    break;
                }
            }
        }
        if(flag)
            printf("Case #%d: Yes\n",++kase);
        else
            printf("Case #%d: No\n",++kase);
    }

    return 0;
}
时间: 2024-12-18 23:38:48

HDU4786 Fibonacci Tree【最小生成树】的相关文章

HDU 4786 Fibonacci Tree 最小生成树变形

思路: 这题比赛的时候想了好久,最后队友机智的想到了. 不过那时不是我敲的,现在敲的1A. 想好就容易了. 直接把1或者0当做边的权值,然后按边从小到大排序,然后算最小生成用到了几条白边,然后再按边从大到小排序,然后再算白边用了几条.然后最小和最大需要用到的白边都算出来了.如果在这最小最大区间中存在那个啥数列的话就是Yes,否则就是No. 为什么在这区间里面就是对的呢?刚开始我也想了好久,然后发现,因为白边权值是1,然后黑边是0,然后假设用到白边最小的是6,最大的是10,那么,我们可以用黑边去替

HDU--4786 Fibonacci Tree 生成树+贪心?

N个顶点,M条边,每条边可能为黑色或是白色( 0 or 1 ),问有没有可能用为斐波那契数的数目的白色边构成一棵生成树.所以需要删掉图中的环,根据每次删掉的边有一个白色边的上限和下限,判断一下中间有没有斐波那契数就可以了.实现方法是根据颜色排序,先放黑色边得到的是最小数目的白色边构成的生成树,先放白色边得到是最大数目的白色边构成的生成树. #include<cstring> #include<string> #include<fstream> #include<i

hdu 4786 Fibonacci Tree ( 最小生成树 )

Fibonacci Tree Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 2487    Accepted Submission(s): 796 Problem Description Coach Pang is interested in Fibonacci numbers while Uncle Yang wants him t

hdu4786 Fibonacci Tree (最小生成树)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4786 题意:给定图的n个点和m条双向边,告诉你每条边的权值.权值为1表示该边是白边,权值为0表示该边为黑边. 问能否找到一颗生成树,使生成树白边的个数刚好为fibonacci数.如果能构成输出yes,否则输出no. 思路:这里有一个点要知道.因为是0,1 tree.   最小生成树<=生成树的值<=最大生成树.  注意,这个区间的任意一个值都能取到. 但是如果不是0,1 tree,权值就不是任意可

【最小生成树】【kruscal】hdu4786 Fibonacci Tree

假设这张图能够形成具有k条白边的生成树, 则易证k一定形成一个连续的区间[a,b],中间一定不会断开.要是断开--tm怎么可能. 所以求出a,b就好啦,人家都给你把白边赋成1了,直接跑一下最小生成树,再跑一下最大生成树即可咯. #include<cstdio> #include<algorithm> using namespace std; #define N 100010 struct Edge{ int u,v,w; }edges[N]; bool cmp(const Edge

[HDOJ4786]Fibonacci Tree 最小生成树

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4786 先跑一遍最小生成树,注意判断是否已全部联通(用一个记号来统计最后生成树中有多少条边).再记下最小生成树的权值和A. 再反向排序,求一遍最大生成树.记下权值和B.问题转换成求[A,B]内是否有斐波那契数存在. 1 #include <algorithm> 2 #include <iostream> 3 #include <iomanip> 4 #include <

hdu 4786 Fibonacci Tree (最小生成树扩展)

///白边优先和黑边优先做两次最小生成树 ///若有斐波那契树在这中间为yes # include <stdio.h> # include <algorithm> # include <iostream> # include <string.h> # include <math.h> using namespace std; struct node { int x; int y; int v; }; struct node a[100010];

Fibonacci Tree(最小生成树,最大生成树)

Fibonacci Tree Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 3006    Accepted Submission(s): 966 Problem Description Coach Pang is interested in Fibonacci numbers while Uncle Yang wants him to

hdu 4786 Fibonacci Tree(最小生成树)

Fibonacci Tree Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 2952    Accepted Submission(s): 947 Problem Description Coach Pang is interested in Fibonacci numbers while Uncle Yang wants him t