Two Famous Companies 【二分+最小生成树】

Problem Description
In China, there are two companies offering the Internet service for the people from all cities: China Telecom and China Unicom. They both are planning to build cables between cities. Obviously, the government wants to connect all the cities in minimum costs. So the minister of finance Mr. B wants to choose some of the
cable plans from the two companies and calculate the minimum cost needed to connect all the cities. Mr. B knows that N-1 cables should be built in order to connect all N cities of China. For some honorable reason, Mr. B should choose K cables from the China Telecom and the rest N-1-K cables from the China Unicom. Your job is to help Mr. B determine which cables should be built and the minimum cost to build them. You may assume that the solution always exists.

Input
Each test case starts with a line containing the number of cities N (1 <= N <= 50,000), number of cable plans M (N-1 <= M <= 100,000) and the number of required
cables from China Telecom K (0 <= K <= N-1). This is followed by M lines, each containing four integers a, b, c, x (0 <= a, b <= N-1, a != b, 1 <= c <= 100, x in {0,1} indicating the pair of cities this cable will connect, the cost to build this cable and the company this cable plan belongs to. x=0 denotes that the cable plan belongs to China Telecom and x=1 denotes that the cable plan is from China Unicom.

Output
For each test case, display the case number and the minimum cost of the cable building.

Sample Input
2 2 1
0 1 1 1
0 1 2 0
2 2 0
0 1 1 1
0 1 2 0

Sample Output
Case 1: 2
Case 2: 1
来源: http://acm.hdu.edu.cn/showproblem.php?pid=4253


大意:有电信和联通两家公司在全省所有城市连电线,规定电信的电线数量,使每两个城市能连接起来。问,最少花费?

题解:
这题出得真tmd牛,搞了好久。
首先,虽然规定了电信电线的数量,但实际给出数据有可能超过规定的数量tel,我们要筛选出最少花费的tel条,同时又不能忘记联通电线的花费,因为有可能比电信的便宜,那么可以得出思路:我们需要动态地衡量电信的电线和联通的电线的花费,在确保选出的tel条电信线花费最少的基础上,使得联通选出来的电线花费也最少。

有这么一个办法:我们设法增加或减少电信电线的价格,这里使用使用二分法,电线价格在-100和100之间,动态增加或减少电信电线的价格,然后所有电线从小到大排序,进行最小生成树。多次二分后就能得出的电信线刚好tel条时的花费,再从总花费中减去增加的那部分花费。

 

#include<stdio.h>
#include<string.h>
#include<algorithm>
#define M 50001
using namespace std;
int set[M];
struct node{
	int s;
	int e;
	int len;
	int com;
}p[M*2+1];
int find(int r){
	int i=r;
	while(set[r] != r){
		r = set[r];
	}
	int j;
	while(i != r){
		j = set[i];
		set[i] = r;
		i = j;
	}
	return r;
}
int merge(int a,int b){
	int A = find(a);
	int B = find(b);
	if(A != B){
		set[B] = A;
		return 1;
	}
	return 0;
}
void init(){
	for(int i=0;i<50001;i++){
		set[i] = i;
	}
}
int cmp(node a,node b){
	if(a.len != b.len){
		return a.len < b.len;
	}else{
		return a.com < b.com;
	}
}
int n,m,tel,sum;
int kru(int x){
	int tel2 = n-1;
	sum = 0;
	int count = 0;
	for(int i=0;i<m;i++){
		if(p[i].com == 0){
			p[i].len += x;
		}
	}
	init();
	sort(p,p+m,cmp);
	for(int i=0;i<m;i++){
		if(merge(p[i].e,p[i].s)){
			sum += p[i].len;
			count++;
			tel2 -= p[i].com;
		}
		if(count == n-1){
			break;
		}
	}
	for(int i=0;i<m;i++){
		if(p[i].com == 0){
			p[i].len -= x;
		}		
	}
	return tel2 >= tel;
}
int main(){
	int cas = 0;
	while(~scanf("%d %d %d",&n,&m,&tel)){
		for(int i=0;i<m;i++){
			scanf("%d %d %d %d",&p[i].s,&p[i].e,&p[i].len,&p[i].com);
		}
		int l = -100,r = 100,mid = 0,ans = 0;
		while(l <= r){
			mid = (l + r)/2;
			if(kru(mid)){
				l = mid + 1;
				ans = sum - mid*tel;
			}else{
				r = mid - 1;
			}
		}
		cas++;
		printf("Case %d: %d\n",cas,ans);
	}
	return 0;
}

  

 

转载于:https://www.cnblogs.com/redscarf/p/6629458.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值