Fibonacci Tree HDU - 4786 (生成樹)
阿新 • • 發佈:2018-12-01
Fibonacci Tree
題意:給出一個圖,每條邊的權值要麼是0,要麼是1,問能否構成一棵生成樹,使得這棵樹的邊權和為斐波那契數;
思路:記圖的最大生成樹和最小生成樹的邊權和分別為max, min,那麼,一定可以構造出合法的生成樹,使得其邊權和在區間[min, max];這是個值得思考的地方;
當我們得到一個最小生成樹後,想要向最大生成樹轉換時,必定是通過換邊解決,而圖中的邊權為1 or 0,所以有四種情況:1->1, 1->0, 0->1, 0->0;這四種情況對於邊權和的貢獻分別為0, -1, 1, 0;所以由min->max的過程中每一個值都必定有對應的生成樹結構出現;
所以只需判斷區間[min, max]之間有沒有斐波那契數就可以了,注意還要判斷圖是否連通;
#include <bits/stdc++.h> using namespace std; const int maxn=1e5+10; int N, M; int pre[maxn]; int find(int x){ return x==pre[x]?pre[x]:pre[x]=find(pre[x]); } bool Union(int x, int y){ int fx=find(x), fy=find(y); if(fx==fy) return false; pre[fx]=fy; return true; } struct node{ int u, v, w; }edge[maxn]; void init(){ for(int i=0; i<=N; i++){ pre[i]=i; } } bool cmp1(node a, node b){ return a.w<b.w; } bool cmp2(node a, node b){ return a.w>b.w; } int Kruskal(){ init(); int ret=0, cnt=0; for(int i=0; i<M; i++){ if(Union(edge[i].u, edge[i].v)){ ret+=edge[i].w; cnt++; } if(cnt==N-1) break; } if(cnt<N-1) return 0; return ret; } bool fib[maxn]; void get_fib(){ memset(fib, false, sizeof(fib)); fib[0]=false; fib[1]=true; fib[2]=true; int cnt=3, f1=1, f2=2; while(1){ int t=f1+f2; f1=f2, f2=t; if(t>=maxn) break; fib[t]=true; } } int main(){ int T, cas=0; scanf("%d", &T); get_fib(); while(T--){ scanf("%d%d", &N, &M); for(int i=0; i<M; i++){ scanf("%d%d%d", &edge[i].u, &edge[i].v, &edge[i].w); } sort(edge, edge+M, cmp1); int minn=Kruskal(); sort(edge, edge+M, cmp2); int maxn=Kruskal(); int flag=0; for(int i=minn; i<=maxn; i++){ if(fib[i]){ flag=1; break; } } printf("Case #%d: ", ++cas); if(flag) printf("Yes\n"); else printf("No\n"); } return 0; }