Fibonacci Tree HDU - 4786 (并查集 生成树 思维题)

xiaoxiao2021-02-28  58

Problem Description   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

大致题意:有n个点,m条边,告诉你每条边是黑色0还是白色1。问你将这些点生成一棵树后,所用连接的边是的白色的数量能否是斐波那契数。

思路:n个点的生成树需要n-1条边,我们首先判断该图是否连通,如果不连通那么直接输出no。接下来,我们需要求出构成树时所能用的最多的白色边数Max和最少白色边数Min。我们可以先用白色的边去构图,用并查集来判断连接的点的数量n’,边数即为n’-1,那么最多白色边数Max=n’-1,然后我们再用黑色的边去构图,同理求出最多的黑色边数n”,那么最少需要的白色边数Min=n-1-n”(因为黑边加白边总边数为n-1)。白色边的数量所能取到的范围即[Min,Max](我们可以这样想,因为最多取Max条白边,最少取Min条白边能构成树,所以每当我们减少一条白边时(不要动那些最少需要的白边)我们都能找到一条黑边使得图依旧连通),然后判断一下这个区间内是否有斐波那契数即可。

代码如下

#include<iostream> #include<algorithm> #include<string> #include<cstdio> #include<cstring> #include<queue> #include<vector> #include<cstring> using namespace std; const int maxn=100005; int pre[maxn]; int vis[100005]; int n,m; struct node { int x,y,c; } edge[maxn]; int find(int x) { int r=x; while (pre[r]!=r) r=pre[r]; int i=x; int j; while(i!=r) { j=pre[i]; pre[i]=r; i=j; } return r; } int solve(int k) { int num=0; for(int i=1;i<=n;i++) pre[i]=i; for(int i=1;i<=m;i++) { if(edge[i].c!=k)//k=1时取黑边构图 ,k=0时取白边构图,k=2时两个都取 { int f1=find(edge[i].x); int f2=find(edge[i].y); if(f1!=f2) { pre[f2]=f1; num++;//每新增一个点,边数加一 } } } return num; } int main() { int f[50];//存放斐波那契数 memset(vis,0,sizeof(vis)); vis[1]=vis[2]=f[1]=1; f[2]=2; for(int i=3;i<=24;i++) { f[i]=f[i-1]+f[i-2]; vis[f[i]]=1;//将斐波那契数标记为1 } int T; scanf("%d",&T); for(int t=1;t<=T;t++) { int flag=0; scanf("%d%d",&n,&m); for(int i=1;i<=m;i++) scanf("%d%d%d",&edge[i].x,&edge[i].y,&edge[i].c); printf("Case #%d: ",t); if(solve(2)!=n-1)//首先判断是否连通 { printf("No\n"); continue; } int Min=n-1-solve(1);//求最少白边 int Max=solve(0);//求最多白边 for(int i=Min;i<=Max;i++) { if(vis[i]==1) { printf("Yes\n"); flag=1; break; } } if(!flag) printf("No\n"); } return 0; }
转载请注明原文地址: https://www.6miu.com/read-41026.html

最新回复(0)