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

Hint

In the first case, there are two cable plans between the only two cities, one from China Telecom and one from
China Unicom. Mr. B needs to choose the one from China Telecom to satisfy the problem requirement even the cost is higher.
In the second case, Mr. B must choose the cable from China Unicom, which leads the answer to 1.

题目分析

这个题目在最小生成树的基础上加了一个限制,那就是其中某一种道路必须有k条,先设想一下暴力法如何解题(我认为暴力法最能体现一个题目的解题思路,优化是为了代替暴力法中的某几个高耗时过程),我们需要找到含有k个电信道路的树中的最小生成树,那么为了找到这个最小生成树,我们需要枚举所有的,含有k个电信的道路树,以此来找到含有k个电信道路中的最小生成树。

那么我们给这个最小生成树中 为电信的道路加上任意权值(对这些道路构建费用的改变),这样就得到了另外一组测试样例(只有道路花费不一样),对于这组新的测试样例,求其在含有k个电信的道路情况下的最小生成树,这个最小生成树一定和没有加权值的最小生成树一样(这里的最小生成树是在含有k个电信道路的情况下的最小生成树)。

对于这个东西的证明,因为我们在没有加上权值的情况下已经把所有含有k个电信的道路的树全部枚举出来了,那么设想在这些树中对某一些道路增加一样的构建费用,其结果当然是在没有加权值的情况下的最小生成树的消耗小(这里的最小生成树是在含有k个电信道路的情况的最小生成树)。

好了,以上就是暴力的解题思路,那么我们要如何优化这个暴力法呢?一般人对于没有加上 含有k个电信的情况下 求最小生成树应该很清楚,那么我们就通过找没有这个限制条件下的最小生成树来得到答案。

由以上证明的那个理论我们知道,对于加上了权值的测试数据和没有加上权值的测试数据,在同样含有k个电信道路的情况下的树中,二者这些树中的最小生成树是一样的。那么,如果加上了权值的道路在没有 “必须含有k个电信道路” 这一条件下得到了最小生成树,这个最小生成树的道路中恰好含有k个电信道路,那么这个最小生成树就是我们需要的答案(再次强调,这里的最小生成树是在含有k个电信道路的情况下的最小生成树)

具体来说,我们通过给所有的电信道路加上某一个权值得到一组新的测试数据,对于这组测试数据,我们抛弃“含有k个电信道路”这一条件得到最小生成树,如果这个最小生成树中含有k个电信道路,那么这个最小生成树的道路结构(也就是树的结构)就是在没有加这个权值的情况下在含有k个电信道路的树中是最优的结构,也是答案需要的树的结构。

对于这个题目,不知道是不是我的翻译有问题,这个题目的要求应该是至少含有k个电信道路吧,但是我将刚好为k作为标准得到的结果是错的,而把至少含有k的电信道路作为标准是对的,如果有问题,望指正,谢谢。

代码区

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
#include<sstream>
#include <iterator>
using namespace std;
#define sf(a) scanf_s("%d",&a)
#define sff(a,b) scanf_s("%d%d",&a,&b)
#define sfff(a,b,c) scanf_s("%d%d%d",&a,&b,&c)
#define sffff(a,b,c,d) scanf_s("%d%d%d%d",&a,&b,&c,&d)
#define slf(a) scanf_s("%lld",&a)
#define ssf(str) scanf_s("%s",str)
#define scf(ch) scanf_s("%c",&ch)
#define mem(s,data) memset(s,data,sizeof(s))
#define inf 0x3f3f3f3f
const int max2 = + ;
const int max3 = + ;
const int max4 = + ;
const int max5 = + ;
typedef long long ll; typedef struct Edge{
int s;
int e;
int v;
Edge(int s = , int e = , int v = ) :s(s), e(e), v(v) {};
bool operator<(const Edge& s)const
{
return this->v < s.v;
}
}Edge; Edge e0[max5], e1[max5]; //分别代表x = 0 , x = 1 的道路
int set[max5]; //代表对应下标的城市的父节点
int n, m, k;
void init(int n);
int build(int a, int len0, int len1,int& sum); int main()
{
int kCase = ;
while(sfff(n,m,k)!=EOF)
{
int s, e, v, ok;
int len0=, len1=; //分别记录x = 0 ,x = 1 的道路的个数
for(int i = ;i < m ; i++)
{
sffff(s, e, v, ok);
if (ok)
e1[len1++] = Edge(s, e, v);
else
e0[len0++] = Edge(s, e, v);
}
sort(e0, e0 + len0);
sort(e1, e1 + len1);
int lSide = -;
int rSide = ; int ans = ;
while(lSide <= rSide)
{
const int mid = (lSide + rSide) >> ;
int sum;
const int order = build(mid, len0, len1, sum);
/*if (order == 0)
{
ans = sum - mid * k;
break;
}*/
if (order >= ) //权值太小,或者刚刚好
lSide = mid + , ans = sum - mid * k;
else //权值太大
rSide = mid - ; }
printf("Case %d: %d\n", ++kCase, ans);
}
return ;
} //初始化父节点,也不知道这个题目怎么想的,居然0也表示城市
void init(int n)
{
for (int i = ; i < n; i++)
set[i] = i;
} //找到对应城市的根结点
int find(int x)
{
if (set[x] == x)
return x;
return set[x] = find(set[x]);
} //给电信的每一条道路加上权值a后寻找没有“必须含有k条电信道路”这一限制条件的最小生成树,
//0表示其中含有k个电信道路,1表示权值太小,导致含有电信道路数过多,0表示权值太大
int build(const int a,const int len0,int len1,int& sum)
{
init(n);
sum = ; //初始化
int index0 = , index1 = ; //分别记录了e0,e1的当前最便宜道路
int ans = ; //记录使用了多少个e0的道路
for(int i = ; i < m ; i++)
{
Edge temp;
int flag = ; //记录要构建的是何种道路
if(index0 >= len0 || index1 < len1 && e1[index1].v < e0[index0].v + a) temp = e1[index1++],flag = ;
else temp = e0[index0++];
int s = find(temp.s);
int e = find(temp.e);
if (s != e)
{
set[s] = e;
sum += temp.v;
if (!flag) //电信的道路有额外的权值
sum += a,ans++;
}
}
if (ans == k)return ;
if (ans > k)return ;
return -;
}

HDU 4253-Two Famous Companies(二分+最小生成树)的更多相关文章

  1. HDU 4253 Two Famous Companies

    Two Famous Companies Time Limit: 15000ms Memory Limit: 32768KB This problem will be judged on HDU. O ...

  2. hdu 4253 Two Famous Companies BZOJ 2654 tree

    [题意]:给出n个点,m条边,边分为两种,一种是A公司的,一种是B公司的.边上有权值,问用n-1条边把n个点连起来的最小费用是多少,其中A公司的边刚好有k条.题目保证有解. 思路:我们发现,如果我们给 ...

  3. HDOJ 4253 Two Famous Companies 二分+MST

    题目意思:给出n个点,m条边,边分为两种,一种是A公司的,一种是B公司的.边上有权值, 问用n-1条边把n个点连起来的最小费用是多少,其中A公司的边刚好有k条.题目保证有解. 题解:题目意思很简单就是 ...

  4. hdu4253 Two Famous Companies --- 二分+MST

    给n个点.m条边的图.每条边要么属于a公司,要么属于b公司.要求一颗最小生成树,条件是当中属于a公司的边数为k. 这题做法非常巧妙. 要求最小生成树,但有一定限制,搜索.贪心显然都不正确. 要是能找到 ...

  5. hdu 3433 A Task Process 二分+dp

    A Task Process Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) T ...

  6. HDU 3622 Bomb Game(二分+2-SAT)

    Bomb Game Time Limit: 10000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total ...

  7. [国家集训队2012]tree(陈立杰) 题解(二分+最小生成树)

    tree 时间限制: 3 Sec  内存限制: 512 MB 题目描述 给你一个无向带权连通图,每条边是黑色或白色.让你求一棵最小权的恰好有need条白色边的生成树. 题目保证有解. 输入 第一行V, ...

  8. SPOJ COMPANYS Two Famous Companies 最小生成树,二分,思路 难度:2

    http://www.spoj.com/problems/COMPANYS/en/ 题目要求恰好有k条0类边的最小生成树 每次给0类边的权值加或减某个值delta,直到最小生成树上恰好有k条边为0,此 ...

  9. hdu 4253(经典题目:二分+最小生成树)

    题意:就是说有A.B两个公司要修路,有m条路,可能是属于A修的,也可能是属于B修的,现在要求所有路都联通的情况下的最小权值,并且A公司必须要修k条路. 同: 代码: #include<iostr ...

随机推荐

  1. 【CUDA 基础】2.3 组织并行线程

    title: [CUDA 基础]2.3 组织并行线程 categories: CUDA Freshman tags: Thread Block Grid toc: true date: 2018-03 ...

  2. Codeforces 1167 F Scalar Queries 计算贡献+树状数组

    题意 给一个数列\(a\),定义\(f(l,r)\)为\(b_1, b_2, \dots, b_{r - l + 1}\),\(b_i = a_{l - 1 + i}\),将\(b\)排序,\(f(l ...

  3. Java当中的基本类型包装类

    Java当中的基本类型包装类 01 基本数据类型对象的包装类 **什么是基本数据类型对象包装类呢?**就是把基本数据类型封装成对象,这样就可以提供更多的操作基本数值的功能了. 基本数据类型对象的包装类 ...

  4. Ubuntu下的redis安装过程

    Redis make test Errors? - Stack Overflow  https://stackoverflow.com/questions/48425998/redis-make-te ...

  5. zabbix监控部署

    zabbix是一款开源的监控软件,下面来一起学习一下zabbix监控的部署吧 环境: 主机名 地址 系统 角色 tiandong 192.168.209.3 centos6.5 服务端 winter ...

  6. [CSP-S模拟测试]:走路(期望DP+分治消元)

    题目传送门(内部题100) 输入格式 第一行两个整数$n,m$,接下来$m$行每行两个整数$u,v$表示一条$u$连向$v$的边.不保证没有重边和自环. 输出格式 $n-1$行每行一个整数,第$i$行 ...

  7. 「HEOI2016/TJOI2016」 排序

    题目链接 戳我 \(Solution\) 这道题在线的做法不会,所以这里就只讲离线的做法. 因为直接排序的话复杂度显然不对.但是如果数列为\(01\)串的话就可以让复杂度变成对的了 那么\(01\)串 ...

  8. TCP最大报文段MSS源码分析

    概述 本文主要对MSS相关的几个字段结合源码流程进行分析: 字段含义 user_mss(tcp_options_received)–用户配置的mss,优先级最高: mss_clamp(tcp_opti ...

  9. TCP之RST报文段

    TCP 首部中的 RST 比特是用于 "复位" 的.一般来说,无论何时一个报文段发往基准的连接(referenced connection)出现错误,TCP 都会发出一个复位报文段 ...

  10. LeetCode 90. 子集 II(Subsets II)

    题目描述 给定一个可能包含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集). 说明:解集不能包含重复的子集. 示例: 输入: [1,2,2] 输出: [ [2], [1], [1,2,2 ...