题意:给一个图,里面的边有黑有白,问是否存在一个生成树,使得里面的白边数量恰好是斐波那契数。N<=10w。
思路:让白边是1,黑边是10w,做一遍最小生成树,得出最多存在多少白边。再让白边为10w,黑边是1,做一遍kruscal,得出最少多少白边,然后再看看这区间[ans1,ans2]里面是否存在斐波那契数就行了,10w以内的一共23个斐波那契数。
感想:由于证明不出来这个结果,导致我一直在想别的思路,好久没做出来。就差一点。一直在想如何给边加权做kruscal,但就是想不到正着反着一样来一次,取个区间。
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
#include <iostream> #include <stdio.h> #include <math.h> #include <stdlib.h> #include <string> #include <string.h> #include <algorithm> #include <vector> #include <queue> #include <set> #include <map> #include <stack> using namespace std; typedef long long LL; const int INF=0x7fffffff; const int MAX_N=10000; int F[50]; int T,N,M; int par[100005]; int tall[100005]; struct edge{ int from; int to; int white; long long cost; friend bool operator<(const edge &a,const edge &b){ return a.cost<b.cost; } }; edge A[100009]; void init(int n){ for(int i=1;i<=n;i++){ par[i]=i; tall[i]=0; } } int find_root(int x){ if(par[x]==x){ return x; } else{ return par[x]=find_root(par[x]); } } void unite(int x,int y){ x=find_root(x); y=find_root(y); if(x==y)return; if(tall[x]<tall[y]){ par[x]=y; } else{ par[y]=x; if(tall[x]==tall[y])tall[x]++; } } bool same(int x,int y){ return find_root(x)==find_root(y); } long long kruskal(){ sort(A,A+M);//将边按照权值从小到大排序 // for(int i=0;i<M;i++){ // cout<<A[i].cost<<"!"<<endl; // } init(N);//初始化并查集 long long ans=0; for(int i=0;i<M;i++){ edge e=A[i]; if(!same(e.from,e.to)){ unite(e.from,e.to); ans+=e.cost; // cout<<ans<<")))"<<endl; } } return ans; } int main(){ F[0]=1; F[1]=2; for(int i=2;i<=23;i++){ F[i]=F[i-1]+F[i-2]; // cout<<F[i]<<endl; } cin>>T; int t=T; while(T--){ scanf("%d%d",&N,&M); memset(A,0,sizeof(A)); for(int i=0;i<M;i++){ scanf("%d%d%d",&A[i].from,&A[i].to,&A[i].white); if(A[i].white==0)A[i].cost=200000; else A[i].cost=1; } long long ans1=kruskal(); int liantong=1; for(int i=2;i<=N;i++){ if(!same(1,i)){ // cout<<"fuck"<<endl; liantong=0; break; } } if(liantong==0){ printf("Case #%d: No\n",t-T); continue; } ans1=ans1%200000; for(int i=0;i<M;i++){ if(A[i].white==1)A[i].cost=200000; else A[i].cost=1; } long long ans2=kruskal(); // cout<<ans1<<"!!"<<ans2<<"!!"<<endl; ans2=ans2%200000; ans2=N-ans2-1; if(ans1>ans2)swap(ans1,ans2); // cout<<ans1<<endl<<ans2<<endl; int flag=0; for(int i=1;i<=23;i++){ if(F[i]>=ans1&&F[i]<=ans2){ flag=1; break; } } if(flag==1){ printf("Case #%d: Yes\n",t-T); } else printf("Case #%d: No\n",t-T); } return 0; }