HDU - 4786 Fibonacci Tree(最小生成树 + 最大生成树)

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 <= 105) and M(0 <= M <= 105). 
  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

题意:给定一棵树,边的颜色为白色或黑色,问是否有白边数为斐波那契数的生成树。

思路:把白边排在前面,求最小生成树可以得到白边最多的情况,把黑边排在前面,再求最小生成树可以得到白边最少的情况。判断两个数中间有没有斐波那契数。

0表示黑白,1表示白边,把白边排在前面相当于求最大生成树,把黑边排在前面相当于求最小生成树。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const int N = 1e5 + 10;

int father[N];
bool vis[N];
int n, m, tot, maxx, minn;

struct node {
    int u,v,w;
}edge[N];

bool cmp1(node a, node b) { ///白边在前
    return a.w > b.w;
}

bool cmp2(node a, node b) { ///黑边在前
    return a.w < b.w;
}

void init() {
    memset(vis, 0, sizeof(vis));
    ll a = 1, b = 1;
    vis[1] = 1;
    while(b < N) {
        ll tmp = a + b;
        a = b;
        b = tmp;
        vis[b] = 1;
    }
}

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

void Union(int x,int y) {
    int tmpx=Find(x);
    int tmpy=Find(y);
    if(tmpx!=tmpy)
    {
        father[tmpx]=tmpy;
    }
}

int kruskal() {
    for(int i = 1; i <= n; i++)
        father[i] = i;
    node now;
    int ans = 0;
    for(int i = 1; i <= m; ++i) {
        now = edge[i];
        if(Find(now.u) != Find(now.v)) {
            Union(now.u, now.v);
            ans += now.w;
        }
    }
    return ans;
}

int main()
{
    init();
    int t, u, v, k, kcase = 0;
    scanf("%d", &t);
    while(t--) {
        scanf("%d%d", &n, &m);
        for(int i = 1; i <= m; ++i) {
            scanf("%d%d%d", &edge[i].u, &edge[i].v, &edge[i].w);
        }

        sort(edge + 1, edge + m + 1, cmp1);
        maxx = kruskal();
        int cnt = 0;
        for(int i = 1; i <= n; ++i) {
            if(father[i] == i) {
                cnt++;
                if(cnt > 1) break;
            }
        }
        if(cnt > 1) {
            printf("Case #%d: No\n", ++kcase);
            continue;
        }

        sort(edge + 1, edge + m + 1, cmp2);
        minn = kruskal();
        cnt = 0;
        for(int i = 1; i <= n; ++i) {
            if(father[i] == i) {
                cnt++;
                if(cnt > 1) break;
            }
        }
        if(cnt > 1) {
            printf("Case #%d: No\n", ++kcase);
            continue;
        }
//        cout<<minn<<' '<<maxx<<'\n';
        bool flag = 0;
        for(int i = minn; i <= maxx; ++i) {
            if(vis[i]) {
                flag = 1;
                break;
            }
        }
        if(flag) printf("Case #%d: Yes\n", ++kcase);
        else printf("Case #%d: No\n", ++kcase);
    }
    return 0;
}

 

全部评论

相关推荐

我已成为0offer的糕手:别惯着,胆子都是练出来的,这里认怂了,那以后被裁应届被拖工资还敢抗争?
点赞 评论 收藏
分享
评论
点赞
收藏
分享
牛客网
牛客企业服务