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

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

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

 #include <cstdio>
#include <algorithm>
using namespace std;
const int MAX_N=;
const int MAX_M=;
int T;
int n,m;
struct Edge
{
int from,to,cost;
}edges[MAX_M]; bool cmp0(const Edge e1,const Edge e2)
{return e1.cost<e2.cost;}
bool cmp1(const Edge e1,const Edge e2)
{return e1.cost>e2.cost;} int parent[MAX_N];
int rankk[MAX_N];
void init(int N)
{
for(int i=;i<=N;i++)
{
parent[i]=i;
rankk[i]=;
}
}
int find(int x)
{
if(parent[x]==x) return x;
return parent[x]=find(parent[x]);
}
void unite(int x,int y)
{
x=find(x);
y=find(y);
if(x==y) return;
if(rankk[x]<rankk[y]) parent[x]=y;
else
{
parent[y]=x;
if(rankk[x]==rankk[y]) rankk[x]++;
}
}
bool same(int x,int y)
{return find(x)==find(y);} int kruscal()
{
int ans=;
init(n);
for(int i=;i<m;i++)
{
if(!same(edges[i].from,edges[i].to))
{
unite(edges[i].from,edges[i].to);
ans+=edges[i].cost;
}
}
return ans;
} int fib[];
void init_fib()
{
fib[]=fib[]=;
for(int i=;fib[i-]<MAX_M;i++)
fib[i]=fib[i-]+fib[i-];
/*
for(int i=0;fib[i]<MAX_M;i++)
printf("%d %d\n",i,fib[i]);
printf("\n");
*/
} int main()
{
init_fib();
freopen("4786.txt","r",stdin);
scanf("%d",&T);
for(int ca=;ca<=T;ca++)
{
scanf("%d%d",&n,&m);
for(int i=;i<m;i++)
scanf("%d%d%d",&edges[i].from,&edges[i].to,&edges[i].cost);
printf("Case #%d: ",ca);
if(n==||m==||m<n-)//所给边数<n-1一定不连通
{
printf("No\n");
continue;
}
sort(edges,edges+m,cmp0);
int left=kruscal();
sort(edges,edges+m,cmp1);
int right=kruscal(); int flag=;
for(int i=;i<=n;i++)//判是否为连通图(重边不影响求MST,但不能仅凭所给边数m判是否连通)
if(!same(,i)){flag=; break;}
if(!flag)
{printf("No\n"); continue;} flag=;
for(int i=;i<;i++)//枚举100000以内的fibonacci数,有进入范围的即可
if(left<=fib[i]&&fib[i]<=right)
{flag=;break;}
if(flag) printf("Yes\n");
else printf("No\n");
}
return ;
}

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

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

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

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

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

最新文章

  1. 【Python】【学习笔记】持续更新
  2. 惊魂web应用宕机记一次网站的紧急恢复
  3. 阻止Application_End事件的解决方案
  4. 【easuyi】---easyui中的验证validatebox自定义
  5. .NET设计模式(6):原型模式(Prototype Pattern)(转)
  6. Javascript模仿C语言的链表实现(增删改查),并且使用控制台输入输出
  7. PyDev下PyQt 的尝试
  8. android v7兼容包RecyclerView的使用(四)——点击事件的不同方式处理
  9. 用T4消除代码重复,对了,也错了
  10. 你确实应该学习并使用的 10 个 C# 特性
  11. vbs 读取txt是读取特定的行
  12. sscanf和正则表达式
  13. Memcached存储命令
  14. 校园网IPv6加速
  15. PHP 获取访问来源
  16. 分别用EasyAR和Vuforia开发AR(入门级)
  17. static 关键字 静态成员变量及静态成员函数
  18. Android的BroadcastReceiver组件
  19. Lua IDE工具-Intellij IDEA+lua插件配置教程(Chianr出品)
  20. cmd中utf-8编码的问题

热门文章

  1. 仿新浪微博短网址PHP实现方案
  2. relative与absolute相结合
  3. A canvas fillText and strokeText example
  4. redhat6.3 64位更新源(使用网易源)全过程记录
  5. 一张图讲解为什么需要自己搭建自己的git服务以及搭建的途径
  6. 【bzoj1031】[JSOI2007]字符加密Cipher
  7. python 性能优化
  8. 产生冠军(set,map,拓扑结构三种方法)
  9. poj 3352 双连通分量
  10. 牵一发动全身【Nhibernate基本映射】