一道结论题:如果最小生成树和最大生成树之间存在fib数,成立。不存在或者不连通则不成立。由于是01图,所以这个区间内的任何生成树都存在。
证明:数学归纳?如果一棵树没有办法再用非树边0边替代1边了,那他就是最小生成树。如果一棵生成树大于最小生成树,那么他显然存在可以被替换的1边,否则会与最小矛盾。最大生成树存在(与最小生成树相等时显然结论成立),那么他一定可以有可以替换的边,所以所有区间内的生成树都存在。
吐槽:我一开始以为要依据fib的性质合并块。。研究好久。。冏。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6 #include<queue> 7 #define dbg(x) cerr << #x << " = " << x <<endl 8 #define dbg2(x,y) cerr<< #x <<" = "<< x <<" "<< #y <<" = "<< y <<endl 9 using namespace std; 10 typedef long long ll; 11 typedef double db; 12 typedef pair<int,int> pii; 13 template<typename T>inline T _min(T A,T B){return A<B?A:B;} 14 template<typename T>inline T _max(T A,T B){return A>B?A:B;} 15 template<typename T>inline char MIN(T&A,T B){return A>B?(A=B,1):0;} 16 template<typename T>inline char MAX(T&A,T B){return A<B?(A=B,1):0;} 17 template<typename T>inline void _swap(T&A,T&B){A^=B^=A^=B;} 18 template<typename T>inline T read(T&x){ 19 x=0;int f=0;char c;while(!isdigit(c=getchar()))if(c=='-')f=1; 20 while(isdigit(c))x=x*10+(c&15),c=getchar();return f?x=-x:x; 21 } 22 const int N=1e5+7; 23 struct thxorz{int u,v,w;}e[N]; 24 struct stothx{int nxt,to;}G[N<<1]; 25 int Head[N],tot; 26 inline void Addedge(int x,int y){ 27 G[++tot].to=y,G[tot].nxt=Head[x],Head[x]=tot; 28 G[++tot].to=x,G[tot].nxt=Head[y],Head[y]=tot; 29 } 30 int vis[N]; 31 void dfs(int x){ 32 vis[x]=1; 33 for(register int j=Head[x];j;j=G[j].nxt)if(!vis[G[j].to])dfs(G[j].to); 34 } 35 int T,n,m,minst,maxst,flag; 36 struct dsu{ 37 int anc[N]; 38 inline void Clear(){for(register int i=1;i<=n;++i)anc[i]=i;} 39 inline int Find(int x){return anc[x]==x?x:anc[x]=Find(anc[x]);} 40 }S; 41 int fib[]={1,1,2,3,5,8,13,21,34,55,89,144,233,377,610,987,1597,2584,4181,6765,10946,17711,28657,46368,75025};//24 42 43 int main(){//freopen("test.in","r",stdin);//freopen("test.ans","w",stdout); 44 read(T);for(register int testcase=1;testcase<=T;++testcase){ 45 read(n),read(m);minst=maxst=flag=0; 46 memset(Head,0,sizeof Head);tot=0; 47 for(register int i=1;i<=m;++i)read(e[i].u),read(e[i].v),read(e[i].w),Addedge(e[i].u,e[i].v); 48 memset(vis,0,sizeof vis);dfs(1); 49 for(register int i=1;i<=n;++i)if(!vis[i]){flag=1;break;} 50 if(flag){printf("Case #%d: No ",testcase);continue;} 51 S.Clear(); 52 for(register int i=1;i<=m;++i)if(!e[i].w)if(S.Find(e[i].u)^S.Find(e[i].v)) 53 S.anc[S.anc[e[i].u]]=S.anc[e[i].v]; 54 for(register int i=1;i<=m;++i)if(e[i].w)if(S.Find(e[i].u)^S.Find(e[i].v)) 55 S.anc[S.anc[e[i].u]]=S.anc[e[i].v],++minst; 56 S.Clear(); 57 for(register int i=1;i<=m;++i)if(e[i].w)if(S.Find(e[i].u)^S.Find(e[i].v)) 58 S.anc[S.anc[e[i].u]]=S.anc[e[i].v],++maxst; 59 for(register int i=1;i<=m;++i)if(!e[i].w)if(S.Find(e[i].u)^S.Find(e[i].v)) 60 S.anc[S.anc[e[i].u]]=S.anc[e[i].v]; 61 int x=lower_bound(fib+1,fib+24,minst)-fib; 62 if(maxst>=fib[x])printf("Case #%d: Yes ",testcase); 63 else printf("Case #%d: No ",testcase); 64 } 65 return 0; 66 }
总结:做生成树问题没有什么其他方法,所以还是最好多往MST上去想。。