Hduoj4786【最小生成树】

来源:互联网 发布:2017年美国进出口数据 编辑:程序博客网 时间:2024/06/17 07:35
#include<stdio.h>#include<stdlib.h>struct point{int x, y, o;}P[100010] ;int f[100010], F[33];void get_Fib(){F[1] = 1;F[2] = 2;for(int i = 3; F[i] <= 30; ++i)F[i] = F[i-1] + F[i-2];}int find(int x){if(x != f[x])f[x] = find(f[x]);return f[x];}int merge(int x, int y){x = find(x);y = find(y);if(x != y){f[x] = y;return 1;}return 0;}int cmp(const void *a, const void *b){return (*(struct point*)a).o - (*(struct point*)b).o;} int main(){int i, j, k, t, n, m, cas = 1;scanf("%d", &t);get_Fib();while(t--){scanf("%d%d", &n, &m);for(i = 0; i < m; ++i)scanf("%d%d%d", &P[i].x, &P[i].y, &P[i].o);printf("Case #%d: ", cas++);qsort(P, m, sizeof(P[0]), cmp);int min = 0, max = 0;for(i = 1; i <= n; ++i)f[i] = i;k = 0;for(i = 0; i < m; ++i){if(merge(P[i].x, P[i].y)){k++;if(P[i].o == 1)min++;}}if(k < n-1){printf("No\n");continue;}for(i = 1; i <= n; ++i)f[i] = i;for(i = m-1; i >= 0; --i){if(merge(P[i].x, P[i].y)){if(P[i].o == 1)max++;}}for(i = 1; ; ++i){if(F[i] >= min && F[i] <= max){printf("Yes\n");break;}if(F[i] > max){printf("No\n");break;}}}return 0;}


题意:给出n个点和m条边,每条边都有颜色,要么是黑色要么是白色,现在求将这n个点连接在一起所构成的边中,白边的个数是否可以为 Fib数。

思路:由于生成树中可以以一条白边替换成黑边构成一个新的生成树,所以我们只要算出白边的最大数和最小数,便可知道白边的个数是否可能为Fib数了。所以我们将边分成2堆,并且分别由白边和黑边入手,求出白边的最大数和最小数,再枚举Fib数即可。

0 0
原创粉丝点击