HDU 4786 Fibonacci Tree(最小生成树)

该题其实就是最小生成树的变形,先求一个最小生成树的权值,再求一个最大生成树的权值,显然在这两个权值之间的所有值都可以取到(你总可以拿一条黑边换成一条白边)。那么我们只要看一下这些值中有没有斐波那契数就行了。小于100000的斐波那契数只有几十个,直接枚举就行了 。 

细节参见代码:

#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
const long long maxn = 100000 + 10;
int T,n,m,p[maxn],kase = 0,tot=0;
ll vis[maxn];
struct node{
    int a,b,c;
    bool operator < (const node& rhs) const {
        return c < rhs.c;
    }
}e[maxn];
int findd(int x) { return p[x] == x ? x : p[x] = findd(p[x]); }
void init() {
    vis[0] = 1; vis[1] = 2;
    tot = 2;
    while(vis[tot-1] < 100000 + 500) {
        vis[tot] = vis[tot-1]+vis[tot-2];
        tot++;
    }
}
bool solve() {
    for(int i=1;i<=n;i++) p[i] = i;
    sort(e,e+m);
    int max_v = 0,min_v = 0 ,cnt = 1;
    for(int i=0;i<m;i++) {
        int x = findd(e[i].a) , y = findd(e[i].b);
        if(x != y) {
            cnt++;
            min_v += e[i].c; p[x] = y;
        }
    }
    if(cnt != n) return false;
    for(int i=1;i<=n;i++) p[i] = i;
    for(int i=m-1;i>=0;i--) {
        int x = findd(e[i].a) , y = findd(e[i].b);
        if(x != y) {
            max_v += e[i].c; p[x] = y;
        }
    }
    for(int i=0;i<tot;i++)
        if(vis[i]>=min_v && vis[i]<=max_v) return true;
    return false;
}
int main() {
    init();
    scanf("%d",&T);
    while(T--){
        scanf("%d%d",&n,&m);
        for(int i=0;i<m;i++)
            scanf("%d%d%d",&e[i].a,&e[i].b,&e[i].c);
        printf("Case #%d: ",++kase);
        if(solve()) printf("Yes\n");
        else printf("No\n");
    }
    return 0;
}


你可能感兴趣的:(最小生成树,图论,并查集,ACM-ICPC)