LA 6540 Fibonacci Tree

题意:

给出一个\(n\)个点\(m\)条边的无向图,每条边的颜色为黑色或者白色。问是否存在一颗生成树使得树上白边的数量为斐波那契数。

分析:

按边的颜色给边排个序,找出白边数量最多的生成树和白边数量最少的生成树。
从白边最少到白边最多的过程中,树上白边的数量是连续变换的。(这个结论不太会证)
所以如果这个区间中有斐波那契数那么答案就是存在
注意要判断一下原图是否连通

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

const int maxn = 100000 + 10;

int n, m;

struct Edge
{
    int u, v, c;
    bool operator < (const Edge& e) const {
        return c > e.c;
    }
}edges[maxn];

int pa[maxn];
int findset(int x) { return x == pa[x] ? x : pa[x] = findset(pa[x]); }

int fib[100];

int main() {
    fib[1] = 1; fib[2] = 2;
    for(int i = 3; i <= 25; i++) fib[i] = fib[i - 1] + fib[i - 2];

    int T; scanf("%d", &T);
    for(int kase = 1; kase <= T; kase++) {
        scanf("%d%d", &n, &m);
        for(int i = 0; i < m; i++) {
            scanf("%d%d%d", &edges[i].u, &edges[i].v, &edges[i].c);
        }
        sort(edges, edges + m);

        for(int i = 1; i <= n; i++) pa[i] = i;
        int cc = n, white1 = 0;
        for(int i = 0; i < m && cc > 1; i++) {
            Edge& e = edges[i];
            int pu = findset(e.u), pv = findset(e.v);
            if(pu == pv) continue;
            cc--;
            pa[pu] = pv;
            if(e.c == 1) white1++;
        }

        if(cc > 1) { printf("Case #%d: No\n", kase); continue; }

        for(int i = 1; i <= n; i++) pa[i] = i;
        cc = n;
        int white2 = 0;
        for(int i = m - 1; i >= 0 && cc > 1; i--) {
            Edge& e = edges[i];
            int pu = findset(e.u), pv = findset(e.v);
            if(pu == pv) continue;
            cc--;
            pa[pu] = pv;
            if(e.c == 1) white2++;
        }

        //printf("%d %d\n", white2, white1);

        bool ok = false;
        for(int i = 1; i <= 24; i++) if(white2 <= fib[i] && fib[i] <= white1) {
            ok = true; break;
        }

        printf("Case #%d: %s\n", kase, ok ? "Yes" : "No");
    }

    return 0;
}

转载于:https://www.cnblogs.com/AOQNRMGYXLMV/p/4909357.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值