hdu 4253(二分+最小生成树)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4253
思路:求最小生成树是显然的,题目还多了一个限制条件,就是属于A公司的边必须有K条,于是我们可以二分来实现这个目的,找一个尽量大的mid,用A公司的每条边都加上这个mid,使得求出的最小生成树中包含A公司的边至少K条,于是花费ans=sum-K*mid。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 #define MAXN 50000+50 7 #define MAXM 100000+100 8 #define inf 1<<30 9 int parent[MAXN]; 10 struct Edge{ 11 int u,v,w; 12 }W[MAXM],B[MAXM]; 13 int n,m,k,sum,cnt,cntw,cntb; 14 15 int Find(int x) 16 { 17 if(x==parent[x]) 18 return x; 19 parent[x]=Find(parent[x]); 20 return parent[x]; 21 } 22 23 int cmp(const Edge &p,const Edge &q) 24 { 25 return p.w<q.w; 26 } 27 28 bool Union(int u,int v) 29 { 30 int r1=Find(u),r2=Find(v); 31 if(r1==r2)return false; 32 parent[r1]=r2; 33 return true; 34 } 35 36 bool Judge(int w) 37 { 38 for(int i=0;i<=n;i++) 39 parent[i]=i; 40 cnt=sum=0; 41 int la=0,lb=0; 42 while(la<cntw||lb<cntb){ 43 if(W[la].w+w<=B[lb].w){ 44 if(Union(W[la].u,W[la].v)){ sum+=W[la].w+w;cnt++; } 45 la++; 46 }else{ 47 if(Union(B[lb].u,B[lb].v))sum+=B[lb].w; 48 lb++; 49 } 50 } 51 if(cnt>=k)return true; 52 return false; 53 } 54 55 56 int main() 57 { 58 // freopen("1.txt","r",stdin); 59 int u,v,w,tag,ans,t=1; 60 while(~scanf("%d%d%d",&n,&m,&k)){ 61 cntw=cntb=0; 62 while(m--){ 63 scanf("%d%d%d%d",&u,&v,&w,&tag); 64 if(tag){ B[cntb].u=u,B[cntb].v=v,B[cntb++].w=w; } 65 else { W[cntw].u=u,W[cntw].v=v,W[cntw++].w=w; } 66 } 67 sort(B,B+cntb,cmp); 68 sort(W,W+cntw,cmp); 69 B[cntb].w=W[cntw].w=inf; 70 int l=-100,r=100,mid; 71 while(l<=r){ 72 mid=(l+r)>>1; 73 if(Judge(mid)){ 74 ans=sum-mid*k; 75 l=mid+1; 76 }else 77 r=mid-1; 78 } 79 printf("Case %d: %d\n",t++,ans); 80 } 81 return 0; 82 }