Description
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
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
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: YesCase #2: No
题意:
给你n个点,m条边,边有黑白两种颜色,问能否用这些边组成一个生成树,使其白色的边的个数为斐波拉切数(1,2,3,5)?
解题思路:
先用 kruskal跑一遍看图是否连通。然后只用白色边构图(用kruskal跑),看最多能用多少白色边(max),然后只用黑色边构图,看最少能用多少白色边(min)。最后枚举斐波拉切数,看是否有在这个范围内成立的斐波拉切数。
为什么找到了max图和min图就能保证一定存在这之间任意数量的白色边的图?
考察min图,加入一条未被用过的白色边,有两种情况
1:这个加入的边刚好覆盖在一条黑色边上,删除此黑色边即可得到min+1的图;
2:这个边没有覆盖任何边,那么只要能从联通这个边的两个节点的通路上删除一条黑色边,就可以min+1的图。假设不存在min+1的图,那么此通路上的所有边都是白色,那么直到把所有白色边都加入图中,任意白色边的两个端点间的通路就都没有黑色边。那么就会得到这样一种情况,最多只有一个节点既能连白色边,又能连黑色边,删除此节点,则得到两个不相连图,一个全是黑色边,一个全是白色边。对于这种情况,可以推出max=min,也就是说只要max>min,这个假设就是错的,所以min+1的图一定存在。
继续考察min+1的图,同上证明。。。可以证明白色边数量在min-max之间所有的图都存在。
好烦人的题目。。。
代码:
#include <iostream> #include <string.h> #include <stdio.h> #include <algorithm> #define maxn 100010 using namespace std; int f[maxn],febo[50]; int n,m; struct edge { int u,v,c; }e[maxn]; int find(int x) { return f[x]==x?x:f[x]=find(f[x]); } int solve(int col) { int num=0; for(int i=1;i<=n;i++)f[i]=i; for(int i=1;i<=m;i++) { if(e[i].c!=col) { int x=find(e[i].u),y=find(e[i].v); if(x!=y) { f[x]=y; num++; } } } return num; } int main() { febo[0]=1,febo[1]=2; int num; for(num=2;;num++) { febo[num]=febo[num-1]+febo[num-2]; if(febo[num]>100000) break; } int ncase,T=0; scanf("%d",&ncase); while(ncase--) { printf("Case #%d: ",++T); scanf("%d%d",&n,&m); for(int i=1;i<=m;i++) scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].c); int tmp,mi,ma,tru=0; tmp=solve(2); if(tmp!=n-1) { printf("No\n"); continue; } ma=solve(0); mi=n-1-solve(1); for(int i=0;i<num;i++) { if(febo[i]>=mi&&febo[i]<=ma) { tru=1; break; } } if(tru) printf("Yes\n"); else printf("No\n"); } return 0; }