【题目】http://acm.hdu.edu.cn/showproblem.php?pid=4786
【题意】给出一个无向图,每个边上有或0或1的权值,问是否存在一个边权和为斐波那契数的生成树?
【思路】毫无头绪...只能说看懂了题解...:实际上,边权只有0和1,那么这个图的生成树的边权和就能取到最小生成树到最大生成树(边权和)之间所有的值。那么只要求出最小生成树和最大生成树即可。
另外注意数据存在不连通的图...
【代码】
#include<bits/stdc++.h>
#define fuck(x) std::cout<<"["<<#x<<"->"<<x<<"]"<<endl;
using namespace std;
typedef long long ll;
const int M=2e5+5;
const int inf=1e9+5;
int n,m;
struct node
{
int u,v,w;
bool operator <(const node a)const
{
return w<a.w;
}
};
vector<node>edge;
int fa[M];
int fndfa(int x)
{
int r=x;
while(r!=fa[r])
r=fa[r];
int i=x,j;
while(i!=r)//优化并查集,不然会T
{
j=fa[i];
fa[i]=r;
i=j;
}
return r;
}
vector<int>fbnq;//斐波那契
void calfbnq()
{
int temp1=1,temp2=1;fbnq.push_back(1);
while(1)
{
int tt=temp2+temp1;
temp1=temp2,temp2=tt;
if(tt>(int)1e5)
break;
fbnq.push_back(tt);
}
}
int main()
{
calfbnq();
int _,cas=0;
scanf("%d",&_);
while(_--)
{
cas++;
edge.clear();
scanf("%d%d",&n,&m);
for(int i=0; i<m; i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
edge.push_back({u,v,w});
}
sort(edge.begin(),edge.end());
//最小生成树
int cnt=0,small=0,big=0;
for(int i=1; i<=n; i++)
{
fa[i]=i;
}
for(int i=0; i<m; i++)
{
int p1=fndfa(edge[i].u),p2=fndfa(edge[i].v);
if(p1!=p2)
{
fa[p1]=p2;
cnt++;
small+=edge[i].w;
}
if(cnt==n-1)
break;
}
if(cnt<n-1)//图竟然可以不连通
{
printf("Case #%d: %s\n",cas,"No");
continue;
}
//最大生成树
cnt=0;
for(int i=1; i<=n; i++)
{
fa[i]=i;
}
for(int i=m-1; i>=0; i--)
{
int p1=fndfa(edge[i].u),p2=fndfa(edge[i].v);
if(p1!=p2)
{
fa[p1]=p2;
cnt++;
big+=edge[i].w;
}
if(cnt==n-1)
break;
}
int ans=0;
for(auto x:fbnq)
{
if(x>=small&&x<=big)
{
ans=1;
break;
}
}
printf("Case #%d: %s\n",cas,ans?"Yes":"No");
}
return 0;
}