题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4786
题意:给定图的n个点和m条双向边,告诉你每条边的权值。权值为1表示该边是白边,权值为0表示该边为黑边。
问能否找到一颗生成树,使生成树白边的个数刚好为fibonacci数。如果能构成输出yes,否则输出no。
思路:这里有一个点要知道。因为是0,1 tree。 最小生成树<=生成树的值<=最大生成树。 注意,这个区间的任意一个值都能取到。
但是如果不是0,1 tree,权值就不是任意可取的了,这个要具体计算的(排列组合,这里先不考虑)。
剩下的看代码很容易懂。
AC代码:
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> using namespace std; #define ll long long const int maxn=1e5+5; const int INF=0x3f3f3f3f; struct Node { int u,v,w; } node[maxn*2]; int n,m; int p[maxn]; int F[30]; int cmp1(Node x,Node y) { return x.w<y.w; } int cmp2(Node x,Node y) { return x.w>y.w; } int Find(int x) { if(x!=p[x]) p[x]=Find(p[x]); return p[x]; } void Union(int x,int y) { x=Find(x); y=Find(y); p[y]=x; } int kruskal() { int q=0,ans=0; for(int i=1; i<=m; i++) { if(Find(node[i].u) != Find(node[i].v)) { ans+=node[i].w; Union(node[i].u,node[i].v); q++; } if(q==n-1) break; } return ans; } int main() { F[1]=1,F[2]=2; int t; for(t=3; F[t]<maxn; t++) F[t]=F[t-1]+F[t-2]; int T; scanf("%d",&T); for(int tt=1; tt<=T; tt++) { scanf("%d%d",&n,&m); for(int i=1; i<=m; i++) scanf("%d%d%d",& node[i].u,& node[i].v,&node[i].w); int minn,maxx; for(int i=1; i<=n; i++) p[i]=i; sort(node+1,node+1+m,cmp1); minn=kruskal(); for(int i=1; i<=n; i++) p[i]=i; sort(node+1,node+1+m,cmp2); maxx=kruskal(); int flag=0; for(int i=1; i<t; i++) if(F[i]>=minn && F[i]<=maxx) { flag=1; break; } int fa=Find(1); for(int i=1; i<=n; i++) if(Find(i)!=fa) { flag=0; break; } if(flag==1) printf("Case #%d: Yes\n",tt); else printf("Case #%d: No\n",tt); } return 0; }
时间: 2024-10-14 19:10:34