hdu4253 二分+MST (经典模型)
n个点,m条边,边分为A,B两类,要构造一棵最小生成树,且树中A边数量为k。
我们可以通过给所有A边加上权值dx来控制树中A边的数量。显然,当dx增大,A边数量kk会减少。
二分dx,
当kk>=k,增大dx(即l=mid+1),同时更新ans=sum(mst)-mid*k;
当kk<k,减小dx(即r=mid-1)。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 struct node 6 { 7 int u,v,w; 8 }ey[110000],el[110000]; 9 int n,m,k,numey,numel,sset[110000],sum; 10 const int mmax=1<<30; 11 int ffind(int x) 12 { 13 if(sset[x]==x) return x; 14 int fa=sset[x]; 15 sset[x]=ffind(fa); 16 return sset[x]; 17 } 18 void mmerge(int a,int b) 19 { 20 int aa=ffind(a); 21 int bb=ffind(b); 22 if(aa!=bb) 23 sset[aa]=bb; 24 } 25 bool cmp(node x1,node y1) 26 { 27 return x1.w<y1.w; 28 } 29 int kruscal(int dx) 30 { 31 int i; 32 sum=0; 33 for(i=0;i<=n;i++) 34 sset[i]=i; 35 int kk=0,posey=0,posel=0,num=0; 36 while(posey<numey||posel<numel) 37 { 38 int from,to; 39 if(ey[posey].w+dx<=el[posel].w) 40 { 41 from=ffind(ey[posey].u); 42 to=ffind(ey[posey].v); 43 if(from!=to) 44 { 45 mmerge(ey[posey].u,ey[posey].v); 46 sum+=(ey[posey].w+dx); 47 kk++; 48 num++; 49 } 50 posey++; 51 } 52 else 53 { 54 from=ffind(el[posel].u); 55 to=ffind(el[posel].v); 56 if(from!=to) 57 { 58 mmerge(el[posel].u,el[posel].v); 59 sum+=el[posel].w; 60 num++; 61 } 62 posel++; 63 } 64 if(num==n-1) break; 65 } 66 if(kk>=k) return 1; 67 else return 0; 68 } 69 int main() 70 { 71 int i,casnum=0; 72 while(scanf("%d%d%d",&n,&m,&k)!=EOF) 73 { 74 numey=numel=0; 75 for(i=0;i<m;i++) 76 { 77 int a,b,c,tmp; 78 scanf("%d%d%d%d",&a,&b,&c,&tmp); 79 if(tmp==0) 80 { 81 ey[numey].u=a; 82 ey[numey].v=b; 83 ey[numey++].w=c; 84 } 85 else 86 { 87 el[numel].u=a; 88 el[numel].v=b; 89 el[numel++].w=c; 90 } 91 } 92 sort(ey,ey+numey,cmp); 93 sort(el,el+numel,cmp); 94 ey[numey].w=el[numel].w=mmax; 95 int l=-100,r=100,mid,ans=0; 96 while(l<=r) 97 { 98 mid=(l+r)/2; 99 if(kruscal(mid)) 100 { 101 l=mid+1; 102 ans=sum-mid*k; 103 } 104 else r=mid-1; 105 } 106 printf("Case %d: %d\n",++casnum,ans); 107 } 108 return 0; 109 }