题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4786
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
Case #1: Yes Case #2: No
题意:
N个顶点,M条边,每条边或为白色或为黑色( 1 or 0 ),
问有没有用是斐波那契数的数目的白色边构成一棵生成树。
PS:
其实说是并查集更靠谱一点的酱紫!
首先判断整个图是否是连通的,若不连通则直接输出No。
接下来首先仅讨论白边,不要黑边,看最多能加入多少条白边,使得不存在环。这样我们得到了能加入白边的最大值max。(就是所有生成树里白边数量的最大值)。
接下来同理仅讨论黑边,这样我们可以得到可加入白边的最小值min,(也可以认为是所有生成树中白边的最小值)。
然后我们只要判断这两个值之间是否存在斐波那契数就行了。
代码如下:
#include <cstdio> #include <cstring> #include <algorithm> #include <iostream> using namespace std; const int maxn = 100017; struct node { int u, v; int c; } a[maxn]; int f[maxn], Fib[maxn]; int n, m; int findd(int x) { return x==f[x] ? x : f[x]=findd(f[x]); } int kruskal(int sign) { int k = 0; //sort(a,a+m,cmp); for(int i = 0; i <= n; i++) { f[i] = i; } for(int i = 1; i <= m; i++) { if(a[i].c != sign) { int f1 = findd(a[i].u); int f2 = findd(a[i].v); if(f1 != f2) { f[f1] = f2; k++; } } } return k; } void init() { Fib[0] = 1, Fib[1] = 2; for(int i = 2; ; i++) { Fib[i] = Fib[i-1]+Fib[i-2]; if(Fib[i] > maxn) break; } } int main() { int t; int cas = 0; init(); scanf("%d",&t); while(t--) { scanf("%d%d",&n,&m); for(int i = 1; i <= m; i++) { scanf("%d%d%d",&a[i].u,&a[i].v,&a[i].c); } int ans = kruskal(2); if(ans != n-1)//不能形成树 { printf("Case #%d: No\n",++cas); continue; } int maxx = kruskal(0); int minn = n-1-kruskal(1); int flag = 0; for(int i = 0; ; i++) { if(Fib[i] >=minn && Fib[i]<=maxx) { flag = 1; break; } if(Fib[i] > maxx) { break; } } if(flag) { printf("Case #%d: Yes\n",++cas); } else { printf("Case #%d: No\n",++cas); } } return 0; }
原文地址:http://blog.csdn.net/u012860063/article/details/40953901