HDU 4253-Two Famous Companies(二分+最小生成树)
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(二分+最小生成树)的更多相关文章
- HDU 4253 Two Famous Companies
Two Famous Companies Time Limit: 15000ms Memory Limit: 32768KB This problem will be judged on HDU. O ...
- hdu 4253 Two Famous Companies BZOJ 2654 tree
[题意]:给出n个点,m条边,边分为两种,一种是A公司的,一种是B公司的.边上有权值,问用n-1条边把n个点连起来的最小费用是多少,其中A公司的边刚好有k条.题目保证有解. 思路:我们发现,如果我们给 ...
- HDOJ 4253 Two Famous Companies 二分+MST
题目意思:给出n个点,m条边,边分为两种,一种是A公司的,一种是B公司的.边上有权值, 问用n-1条边把n个点连起来的最小费用是多少,其中A公司的边刚好有k条.题目保证有解. 题解:题目意思很简单就是 ...
- hdu4253 Two Famous Companies --- 二分+MST
给n个点.m条边的图.每条边要么属于a公司,要么属于b公司.要求一颗最小生成树,条件是当中属于a公司的边数为k. 这题做法非常巧妙. 要求最小生成树,但有一定限制,搜索.贪心显然都不正确. 要是能找到 ...
- hdu 3433 A Task Process 二分+dp
A Task Process Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) T ...
- HDU 3622 Bomb Game(二分+2-SAT)
Bomb Game Time Limit: 10000/3000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total ...
- [国家集训队2012]tree(陈立杰) 题解(二分+最小生成树)
tree 时间限制: 3 Sec 内存限制: 512 MB 题目描述 给你一个无向带权连通图,每条边是黑色或白色.让你求一棵最小权的恰好有need条白色边的生成树. 题目保证有解. 输入 第一行V, ...
- SPOJ COMPANYS Two Famous Companies 最小生成树,二分,思路 难度:2
http://www.spoj.com/problems/COMPANYS/en/ 题目要求恰好有k条0类边的最小生成树 每次给0类边的权值加或减某个值delta,直到最小生成树上恰好有k条边为0,此 ...
- hdu 4253(经典题目:二分+最小生成树)
题意:就是说有A.B两个公司要修路,有m条路,可能是属于A修的,也可能是属于B修的,现在要求所有路都联通的情况下的最小权值,并且A公司必须要修k条路. 同: 代码: #include<iostr ...
随机推荐
- mac重启nginx时报nginx.pid不存在的解决办法
在安装nginx后,重启时发现报 nginx: [error] open() "/usr/local/var/run/nginx.pid" failed (2: No such f ...
- jquery判断元素是否可见隐藏
<!DOCTYPE html> <html> <head> <meta charset=" utf-8"> <meta nam ...
- HTML5属性备忘单
在网上闲逛的时候看到了文章,感觉总结的这个html5文章,决定转载过来,在排版的时候也帮助自己重新梳理复习一遍.毕竟学习基础最重要. by zhangxinxu from http://www.zha ...
- 「SDOI2017」数字表格
题目链接 问题分析 \[ \begin{aligned} Ans&=\prod_{i=1}^n\prod_{j=1}^mf[\gcd(i,j)]\\ &=\prod_{t=1}^nf( ...
- python中的定时器threading.Timer
由浅入深学SQL Server 2012 --> python开发中用到,定时操作.例如每隔1s执行一次,发现 threading.Timer,这个东西,可以直接用. 其原理为执行函数中置定时 ...
- Oracle Stream 同步数据
1 引言 Oracle官方网: http://www.stanford.edu/dept/itss/docs/oracle/10g/server.101/b10727/strmover.htm ...
- spring boot知识清单
https://mp.weixin.qq.com/s/q8OI2Ou8-gYP-usjToBbkQ
- Constructor、Method、Field 源码阅读
AnnotatedElement /** * AnnotatedElement 接口表示目前正在此 VM 中运行的应用程序的一个已注解元素[类.方法.属性]. * 该接口允许反射性地读取注解.此接口中 ...
- linux/windows/Mac平台生成随机数的不同方法
linux平台,使用rand.Seed() //rand_linux.go package main import ( "math/rand" "time" ) ...
- 基于durid的JDBCUtils工具类
1.JDBCUtils类 package com.alphajuns.utils; import com.alibaba.druid.pool.DruidDataSourceFactory; impo ...