首页 > 代码库 > HDU 4786 Fibonacci Tree 最小生成树变形
HDU 4786 Fibonacci Tree 最小生成树变形
思路:
这题比赛的时候想了好久,最后队友机智的想到了。
不过那时不是我敲的,现在敲的1A。
想好就容易了。
直接把1或者0当做边的权值,然后按边从小到大排序,然后算最小生成用到了几条白边,然后再按边从大到小排序,然后再算白边用了几条。然后最小和最大需要用到的白边都算出来了。如果在这最小最大区间中存在那个啥数列的话就是Yes,否则就是No。
为什么在这区间里面就是对的呢?刚开始我也想了好久,然后发现,因为白边权值是1,然后黑边是0,然后假设用到白边最小的是6,最大的是10,那么,我们可以用黑边去替代两条白边,生成树就是有8条白边了,而正好是我们要找的数列中的数。其实还是有点抽象……自己脑子想想吧……
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<map> #include<queue> #include<set> #include<cmath> #include<bitset> #define mem(a,b) memset(a,b,sizeof(a)) #define lson i<<1,l,mid #define rson i<<1|1,mid+1,r #define INF 510010 #define maxn 1000010 using namespace std; typedef long long ll; typedef unsigned long long ull; int f[maxn],fib[92]; struct abc { int u,v,w; }a[maxn]; bool cmp1(abc a,abc b) { return a.w<b.w; } bool cmp2(abc a,abc b) { return a.w>b.w; } void Fib() { fib[1]=1;fib[2]=2; for(int i=3;i<41;i++) fib[i]=fib[i-1]+fib[i-2]; } int find(int x) { return x==f[x]?x:f[x]=find(f[x]); } void init() { for(int i=0;i<maxn;i++) f[i]=i; } int kruscal(int n,int m) { init(); int i,sum=0,num=0,flag=1; for(i=0;i<n&&flag;i++) { int x=find(a[i].u); int y=find(a[i].v); if(x!=y) { f[y]=x; sum+=a[i].w; num++; } if(num==m-1) flag=0; } if(!flag) return sum; else return -1; } int main() { //freopen("test.txt","r",stdin); int t; cin>>t; Fib(); for(int kk=1;kk<=t;kk++) { int n,m,i; scanf("%d%d",&n,&m); for(i=0;i<m;i++) scanf("%d%d%d",&a[i].u,&a[i].v,&a[i].w); sort(a,a+m,cmp1); int sum1=kruscal(m,n); sort(a,a+m,cmp2); int sum2=kruscal(m,n); int cnt1=lower_bound(fib+1,fib+41,sum1)-fib; int cnt2=lower_bound(fib+1,fib+41,sum2)-fib; if(sum1==-1) printf("Case #%d: No\n",kk);//不存在最小生成树 else if(cnt1!=cnt2||cnt1==cnt2&&sum1==sum2&&fib[cnt1]==sum1) printf("Case #%d: Yes\n",kk); else printf("Case #%d: No\n",kk); } return 0; }
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。