【HDU 4786 Fibonacci Tree】最小生成树

一个由n个顶点m条边(可能有重边)构成的无向图(可能不连通),每条边的权值不是0就是1。

给出n、m和每条边的权值,问是否存在生成树,其边权值和为fibonacci数集合{1,2,3,5,8...}中的一个。

求最小生成树和最大生成树,得到生成树边权和的下界left和上界right。这道题由于每条边权值不是0就是1,因此生成树边权和可以覆盖到[left,right]的每一个数。那么求得[left,right],看是否有fibonacci数在区间内就可以了。

  1 #include <cstdio>
  2 #include <algorithm>
  3 using namespace std;
  4 const int MAX_N=100005;
  5 const int MAX_M=100005;
  6 int T;
  7 int n,m;
  8 struct Edge
  9 {
 10     int from,to,cost;
 11 }edges[MAX_M];
 12
 13 bool cmp0(const Edge e1,const Edge e2)
 14 {return e1.cost<e2.cost;}
 15 bool cmp1(const Edge e1,const Edge e2)
 16 {return e1.cost>e2.cost;}
 17
 18 int parent[MAX_N];
 19 int rankk[MAX_N];
 20 void init(int N)
 21 {
 22     for(int i=0;i<=N;i++)
 23     {
 24         parent[i]=i;
 25         rankk[i]=0;
 26     }
 27 }
 28 int find(int x)
 29 {
 30     if(parent[x]==x) return x;
 31     return parent[x]=find(parent[x]);
 32 }
 33 void unite(int x,int y)
 34 {
 35     x=find(x);
 36     y=find(y);
 37     if(x==y) return;
 38     if(rankk[x]<rankk[y]) parent[x]=y;
 39     else
 40     {
 41         parent[y]=x;
 42         if(rankk[x]==rankk[y]) rankk[x]++;
 43     }
 44 }
 45 bool same(int x,int y)
 46 {return find(x)==find(y);}
 47
 48 int kruscal()
 49 {
 50     int ans=0;
 51     init(n);
 52     for(int i=0;i<m;i++)
 53     {
 54         if(!same(edges[i].from,edges[i].to))
 55         {
 56             unite(edges[i].from,edges[i].to);
 57             ans+=edges[i].cost;
 58         }
 59     }
 60     return ans;
 61 }
 62
 63 int fib[25];
 64 void init_fib()
 65 {
 66     fib[0]=fib[1]=1;
 67     for(int i=2;fib[i-1]<MAX_M;i++)
 68         fib[i]=fib[i-1]+fib[i-2];
 69 /*
 70     for(int i=0;fib[i]<MAX_M;i++)
 71         printf("%d %d\n",i,fib[i]);
 72     printf("\n");
 73 */
 74 }
 75
 76 int main()
 77 {
 78     init_fib();
 79     freopen("4786.txt","r",stdin);
 80     scanf("%d",&T);
 81     for(int ca=1;ca<=T;ca++)
 82     {
 83         scanf("%d%d",&n,&m);
 84         for(int i=0;i<m;i++)
 85             scanf("%d%d%d",&edges[i].from,&edges[i].to,&edges[i].cost);
 86         printf("Case #%d: ",ca);
 87         if(n==1||m==0||m<n-1)//所给边数<n-1一定不连通
 88         {
 89             printf("No\n");
 90             continue;
 91         }
 92         sort(edges,edges+m,cmp0);
 93         int left=kruscal();
 94         sort(edges,edges+m,cmp1);
 95         int right=kruscal();
 96
 97         int flag=1;
 98         for(int i=2;i<=n;i++)//判是否为连通图(重边不影响求MST,但不能仅凭所给边数m判是否连通)
 99             if(!same(1,i)){flag=0; break;}
100         if(!flag)
101             {printf("No\n"); continue;}
102
103         flag=0;
104         for(int i=0;i<25;i++)//枚举100000以内的fibonacci数,有进入范围的即可
105             if(left<=fib[i]&&fib[i]<=right)
106                 {flag=1;break;}
107         if(flag) printf("Yes\n");
108         else printf("No\n");
109     }
110     return 0;
111 }

开始觉得可以按一种贪心策略求得一个最优解,如果命中不了fibonacci数则无解。

想贪心的先选权值为0的边,画图发现可能错过fibonacci数,贪心的先选权值为1的边依然可能错过。

画各种例子,发现割边是必须取的,因此边权和有个下界。去掉割边后剩下的就是圈了,每个圈去掉一条边即得生成树;想枚举每个圈的所有情况看能不能命中fibonacci数,但并是不会实现,尤其对很复杂的图。

队友提出过求出上下界然后看是否有fibonacci数在之间,无奈我开始没听懂。。。

另,用m>=n-1判连通的话,m是去掉重边后的边数,WA在这里实在是。。。唉

时间: 2025-01-02 07:58:34

【HDU 4786 Fibonacci Tree】最小生成树的相关文章

hdu 3117 Fibonacci Numbers

点击此处即可传送到hdu 3117 **Fibonacci Numbers** Problem Description The Fibonacci sequence is the sequence of numbers such that every element is equal to the sum of the two previous elements, except for the first two elements f0 and f1 which are respectively

hdu 1568 Fibonacci

点击此处即可传送hdu 1568 **Fibonacci** Problem Description 2007年到来了.经过2006年一年的修炼,数学神童zouyu终于把0到100000000的Fibonacci数列 (f[0]=0,f[1]=1;f[i] = f[i-1]+f[i-2](i>=2))的值全部给背了下来. 接下来,CodeStar决定要考考他,于是每问他一个数字,他就要把答案说出来,不过有的数字太长了.所以规定超过4位的只要说出前4位就可以了,可是CodeStar自己又记不住.于

hdu 1021 Fibonacci Again

点击此处即可传送hdu 1021 Fibonacci Again Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 44439 Accepted Submission(s): 21214 Problem Description There are another kind of Fibonacci numbers: F(0) = 7, F(1)

【HDU 4463 Outlets】最小生成树(prim,kruscal都可)

以(x,y)坐标的形式给出n个点,修建若干条路使得所有点连通(其中有两个给出的特殊点必须相邻),求所有路的总长度的最小值. 因对所修的路的形状没有限制,所以可看成带权无向完全图,边权值为两点间距离.因是稠密图,故用邻接矩阵存储更好(完全图,边数e达到n(n-1)/2). 至此,可将问题抽象为求最小生成树的边权和. 用了prim+邻接矩阵,prim+邻接表+堆,kruscal各写了一遍,只是内存稍有差别 对于所给的特殊的两个相邻点,只需在开始循环前把这两个点加入子树集合并更新它们所到达的点的min

HDOJ(HDU) 1708 Fibonacci String

Problem Description After little Jim learned Fibonacci Number in the class , he was very interest in it. Now he is thinking about a new thing – Fibonacci String . He defines : str[n] = str[n-1] + str[n-2] ( n > 1 ) He is so crazying that if someone g

hdu 2855 Fibonacci Check-up

点击打开hdu 2855 思路: 递推+矩阵快速幂 分析: 1 题目的意思是给定n和m,要求    2 这一题有两种思路,对于这种的题肯定是有递推式的,那么找不到递推式的时候我们尝试去打表    下面我打出了前几十项,发现了n >= 2的时候有f(n) = 3*f(n-1)-f(n-2),那么我们可以利用矩阵快速幂求f(n)    3 另一种思路是考虑f(n) = f(n-1) + f(n-2),那么我们可以利用矩阵求出任意的f(n)    1 1 *  f(n-1) = f(n)    1 0

hdu 1848 Fibonacci again and again

这是尼姆博弈的变型; 还是博弈,但是这次要用Sg函数最后异或等于0后手赢 反之,先手赢 #include <iostream> #include <cstring> #include <cstdio> using namespace std; int f[100]={1,2,3,5}; int e[1005]={0,1,2,3}; int b[16]; void Init() { for(int i=3; f[i-1]<=1000; i++) f[i] = f[i

hdu 4463 Outlets

点击打开链接hdu 4463 思路:最小生成树+kruskal 分析: 1 题目要求的找到n个商店组成n-1条边,并且要求耐克和苹果商店肯定要相连,求最短长度 2 很明显的最小生成树的模板题,由于要求耐克和苹果的商店要在一起那么就要把这两个商店编号合并到同一个集合,然后在利用kruskal计算. 代码: #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #inc

可视化的数据结构和算法

导读:作者陈皓之前写过关于可视化排序的一篇文章,现在他又给大家罗列出可视化的数据结构和算法来供大家学习参考.文中分别从基础.索引.排序.动态编程等方面进行描述. 文章内容如下: 还记得之前发布过的那个关于可视化排序的文章吗?在网上又看到了一个旧金山大学David Galles做的各种可视化的数据结构和基本算法的主页,网址在这里,大家可以看看.我把这个页面的目录列在下面并翻译了一下,大家可以直接点击了. 不知道国内的教育有没有相关的教学课件,至少在我大学的时候是没有的. 基础 Stack栈: 数组