HDU-4786 Fibonacci Tree(最小生成树[Kruskal])

Fibonacci Tree

Time Limit : 4000/2000ms (Java/Other)   Memory Limit : 32768/32768K (Java/Other)

Problem Description

  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

区域赛都是有思维难度的题吧,果然还是不够熟悉图,完全没有思路。

看了别人的题解也才知道:

如果一棵生成树最少含有low条白边,最多含有hig条白边,那么含有x(low<=x&&x<=hig)条白边的生成树一定存在

不知道为什么中间的每一个生成树都存在(望大神告知),但我自己画了几个图还没找出反例


#include <cstdio>
#include <algorithm>

using namespace std;

struct Edge {
    int s,e,c;
    Edge(int ss=0,int ee=0,int cc=0):s(ss),e(ee),c(cc) {}
    bool operator < (const Edge& a) const {
        return c<a.c;
    }
}g[100005];

int par[100005],pa,pb,f[25];

int getPar(int a) {
    if(par[a]!=a)
        par[a]=getPar(par[a]);
    return par[a];
}

void Merge(int a,int b) {
    pa=getPar(a),pb=getPar(b);
    if(pa!=pb)
        par[pb]=pa;
}

int main() {
    int n,m,i,T,kase=0,cnt,low,hig;
    bool flag;
    i=1,f[0]=1,f[1]=2;
    while(f[i]<100005) {
        f[i+1]=f[i]+f[i-1];
        ++i;
    }
    scanf("%d",&T);
    while(kase<T) {
        scanf("%d%d",&n,&m);
        low=hig=0,cnt=1;
        for(i=0;i<m;++i)
            scanf("%d%d%d",&g[i].s,&g[i].e,&g[i].c);
        for(i=1;i<=n;++i)
            par[i]=i;
        sort(g,g+m);
        for(i=0;i<m&&cnt!=n;++i) {
            if(getPar(g[i].s)!=getPar(g[i].e)) {
                Merge(g[i].s,g[i].e);
                ++cnt;
                low+=g[i].c;
            }
        }
        flag=false;
        if(cnt==n) {//如果图是连通的
            cnt=1;
            for(i=1;i<=n;++i)
                par[i]=i;
            for(i=m-1;i>=0&&cnt!=n;--i) {
                if(getPar(g[i].s)!=getPar(g[i].e)) {
                    Merge(g[i].s,g[i].e);
                    ++cnt;
                    hig+=g[i].c;
                }
            }
            i=0;
            while(f[i]<low)
                ++i;
            if(f[i]<=hig)
                flag=true;
        }
        printf("Case #%d: %s\n",++kase,flag?"Yes":"No");
    }
    return 0;
}


你可能感兴趣的:(最小生成树,图论,HDU,kruskal)