题意:给你一个图有白边,和黑边,白边权值为1,黑边权值为0,问有没有一颗生成树,使得白边的条数为斐波拉契数列中的数,如果有就输出Yes没有就No。
思路:求一遍最小生成树的和x,然后求一遍最大生成树的和y,然后枚举这个区间看看有没有斐波拉契数列的数。
这里只有0,1边,假设10个点那么生成树的边就是9条假如最小生成树的权值为6,最大生成树的权值为9
那么,由最小生成树变成最大生成树,实际上是将最小生成树中三条权为0的边替换成了三条为1的边。
那么替换一条 生成树 为1的边就是7,两条就是8。是可以替换的。
代码:
#include<stdio.h>
#include<string.h>
#include<vector>
#include<algorithm>
using namespace std;
#define MAX
struct edge
{
int from,to;
bool w;
};
vector<edge>edges;
int a[30];
int n,m;
bool vis[100010];
int pre[100010];
int mi,ma;
void addedge(int x,int y,double w)
{
edge v={x,y,w};
edges.push_back(v);
}
bool cmp( edge a, edge b){
return a.w < b.w; //<升序,>降序
}
bool cmp1( edge a, edge b){
return a.w > b.w; //<升序,>降序
}
void addedge(int x,int y,int w)
{
edge v={x,y,w};
edges.push_back(v);
}
int find(int x)
{
if(x==pre[x])
{
return x;
}
else
{
pre[x]=find(pre[x]);
return pre[x];
}
}
int kluska()
{
for(int i=1;i<=n;i++)
{
pre[i]=i;
}
int top=n;
for(int i=0;i<edges.size();i++)
{
edge v=edges[i];
int f1=find(v.from);
int f2=find(v.to);
if(f1!=f2)
{
pre[f2]=f1;
top--;
ma+=v.w;
if(top==1) break;
}
}
if(top==1) return 1;
return 0;
}
int kluska2()
{
for(int i=1;i<=n;i++)
{
pre[i]=i;
}
int top=n;
for(int i=0;i<edges.size();i++)
{
edge v=edges[i];
int f1=find(v.from);
int f2=find(v.to);
if(f1!=f2)
{
pre[f2]=f1;
top--;
mi+=v.w;
if(top==1) break;
}
}
if(top==1) return 1;
return 0;
}
int main()
{
a[1]=1;
a[2]=2;
for(int i=3;i<=25;i++)
{
a[i]=a[i-1]+a[i-2];
}
// printf("%d\n",a[25]);
int t;
scanf("%d",&t);
int cas=1;
int s1=0,s0=0;
while(t--)
{
scanf("%d %d",&n,&m);
int x,y,id;
int ans=0;
edges.clear();
for(int i=1;i<=m;i++)
{
scanf("%d %d %d",&x,&y,&id);
addedge(x,y,id);
}
ma=mi=0;
sort(edges.begin(),edges.end(),cmp);
if(!kluska()) {
printf("Case #%d: No\n",cas++);
continue;
}
sort(edges.begin(),edges.end(),cmp1);
kluska2();
int flag=1;
// printf("%d %d\n",mi,ma);
for(int i=ma;i<=mi&&flag;i++)
{
for(int j=1;j<=25&&flag;j++)
{
if(a[j]==i)
{
printf("Case #%d: Yes\n",cas++);
flag=0;
}
if(a[j]>i) break;
}
}
if(flag) printf("Case #%d: No\n",cas++);
}
}