给你一个无向带权连通图,每条边是黑色或白色。让你求一棵最小权的恰好有need条白色边的生成树。
题目保证有解。
V<=50000,E<=100000,所有数据边权为[1,100]中的正整数。
分析:
在大鸡哥的博客里看到的,一开始的分析就是直接一波玄学排序然后暴力Kruskal+一堆判断,然后自己把自己推翻了。。。
还是看了大鸡哥的博客才懂得。大鸡哥的博客里讲的很清晰了,而且还讲到了COGS上和BZOJ上数据不同的问题。就推荐一下大鸡哥的博客吧。
Code:
1 //It is made by HolseLee on 1st June 2018 2 //BZOJ 2654/COGS 1764 3 #include<bits/stdc++.h> 4 using namespace std; 5 const int N=5e4+7; 6 const int M=1e5+7; 7 int n,m,k,fa[N],num,ans; 8 struct Node{ 9 int from,to,val,c,id; 10 }edge[M]; 11 inline int read() 12 { 13 char ch=getchar();int num=0;bool flag=false; 14 while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)flag=true;ch=getchar();} 15 while(ch>=‘0‘&&ch<=‘9‘){num=num*10+ch-‘0‘;ch=getchar();} 16 return flag?-num:num; 17 } 18 inline bool cmp(Node a,Node b) 19 {return a.c==b.c?a.id<b.id:a.c<b.c;} 20 inline int find(int x) 21 {return fa[x]==x?x:fa[x]=find(fa[x]);} 22 inline int check(int ka) 23 { 24 for(int i=1;i<=m;i++) 25 edge[i].c=edge[i].val+(edge[i].id^1)*ka; 26 sort(edge+1,edge+m+1,cmp); 27 for(int i=0;i<n;i++)fa[i]=i; 28 int cnt=0,tot=0;num=0; 29 for(int i=1;i<=m;i++){ 30 int x=find(edge[i].from); 31 int y=find(edge[i].to); 32 if(x!=y){fa[y]=x;tot++; 33 cnt+=(edge[i].id==0?1:0); 34 num+=edge[i].c;} 35 if(tot==n-1)break;} 36 return cnt; 37 } 38 int main() 39 { 40 freopen("nt2012_tree.in","r",stdin); 41 freopen("nt2012_tree.out","w",stdout); 42 scanf("%d%d%d",&n,&m,&k); 43 for(int i=1;i<=m;i++){ 44 scanf("%d%d",&edge[i].from,&edge[i].to); 45 scanf("%d%d",&edge[i].val,&edge[i].id);} 46 int L=-100,R=100,mid; 47 while(L<=R){ 48 mid=(L+R)/2; 49 if(check(mid)>=k)ans=num-k*mid,L=mid+1; 50 else R=mid-1;} 51 printf("%d",ans);return 0; 52 }
BZOJ2654/COGS1764 [2012国家集训队]tree(陈立杰) [生成树,二分]
原文:https://www.cnblogs.com/cytus/p/9123721.html