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;
}
posted @ 2015-10-25 19:36  AOQNRMGYXLMV  阅读(140)  评论(0编辑  收藏  举报