bnuoj25660 Two Famous Companies
题目链接:https://www.bnuoj.com/v3/problem_show.php?pid=25660
这个二分真的是烧脑QAQ,想了一晚上才懂了一个大概。
首先,整体思路是二分,直观上感受一下,就是给第0类边加一个权值,这个权值越大,会让第0类边选的个数变少;权值变小,会上第0类边的个数变多。所以二分这个权值,使得选出来的边的个数是k。
关键是怎么去做这个二分。对于一个mid(当前的权值二分点),我们去做最小生成树的时候,要给边排序,在给边排序的时候,第一关键字是边权,第二关键字是类别,要让同等权值的第0类排在前面。这样可以保证,做最小生成树的时候,求得的解是所有最小生成树里第0类边的个数最多的。当然,最小生成树中也可能存在比这个条数少的。
那么假设我们现在做最小生成树,得到了一个选择t条第0类边的解。如果t<k,那这个权值肯定是没戏了,最多能选出来的第0类边都不够k条,因此权值需要变小一点,让边数变多一点;如果t>=k,说明这里面可能有一个包含k条第0类边的解,所以权值(说不定)可以更大一些。
那么这里要认清一个事实:对于k条第0类边的解来说,随着权值的上升,得到的最小生成树的权值必定是不减的,而且选出来的第0类边的个数必定是不增的。假设原来给第0类边加的权值是X,现在是X',最小生成树的权值是W,权值上升后是W',原来的条数是C,权值上升后是C'。那么有X'>X,W'>=W,C'<=C。如果两个里面都有一个包含k条第0类边的解,那么哪一个更优呢?W'-kX'和W-kX,貌似看不出来啊QAQ。但是结论是,所有k条第0类边构成的解的最小生成树,W-kX都是一样的。为什么呢?其实可以这样考虑,每一个增加权值构成的新的图,形成的最小生成树,都跟原图的一个生成树对应。那么假设原图有若干个恰好包含k条第0类边的权值最小的生成树。那么每一个增加权值后得到的k个第0类边的最小生成树都是跟原来的一一对应的。
那么也就是说我们只需要找到一个即可。那么这个解该怎么找呢?
答案是:就是找让t>=k的那个最大的mid一定有一个包含k条第0类边的解。这个可以用反证法。假设这个不包含=k的解。而又有t>=k,所以t>k。那么随着mid减小,t会越来越大,那所有的都没有包含k的解了。但是题目说一定存在一个包含k条第0类边的解,因此矛盾了。
天啊,终于说完了。直接看代码吧。
#include<bits/stdc++.h>
using namespace std; const int maxn=100005;
struct Edge
{
int u,v,w,x,id;
Edge(){}
Edge(int _u,int _v,int _w,int _x):u(_u),v(_v),w(_w),x(_x){}
bool operator<(Edge&e)
{
return w<e.w||w==e.w&&x<e.x;
}
};
Edge edge_ini[maxn];
Edge edge[maxn];
int fa[50005];
const int INF=0x3f3f3f3f; int findfa(int x)
{
if (x==fa[x]) return x;
return fa[x]=findfa(fa[x]);
} int main()
{
int n,m,k;
int cas=0;
while (~scanf("%d%d%d",&n,&m,&k))
{
for (int i=0;i<m;i++)
{
scanf("%d%d%d%d",&edge_ini[i].u,&edge_ini[i].v,&edge_ini[i].w,&edge_ini[i].x);
edge_ini[i].id=i;
}
int l=-101,r=101;
int ans=INF;
while (l<=r)
{
int mid=(l+r)/2;
for (int i=0;i<m;i++)
{
edge[i].u=edge_ini[i].u;
edge[i].v=edge_ini[i].v;
edge[i].id=edge_ini[i].id;
edge[i].x=edge_ini[i].x;
if (edge_ini[i].x==0)
{
edge[i].w=edge_ini[i].w+mid;
}
else
{
edge[i].w=edge_ini[i].w;
}
}
sort(edge,edge+m);
int now=0;
int now0=0;
int t=0;
for (int i=0;i<n;i++) fa[i]=i;
for (int i=0;i<m;i++)
{
if (now==n-1) break;
int u=edge[i].u;
int v=edge[i].v;
int x=edge[i].x;
int f1=findfa(u);
int f2=findfa(v);
if (f1!=f2)
{
now++;
if (x==0) now0++;
fa[f1]=f2;
t+=edge[i].w;
}
}
if (now0>=k)
{
l=mid+1;
ans=t-k*mid;
}
else r=mid-1;
}
printf("Case %d: %d\n",++cas,ans);
}
return 0;
}
bnuoj25660 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(二分+最小生成树)
Description In China, there are two companies offering the Internet service for the people from all ...
- hdu 4253 Two Famous Companies BZOJ 2654 tree
[题意]:给出n个点,m条边,边分为两种,一种是A公司的,一种是B公司的.边上有权值,问用n-1条边把n个点连起来的最小费用是多少,其中A公司的边刚好有k条.题目保证有解. 思路:我们发现,如果我们给 ...
- SPOJ COMPANYS Two Famous Companies 最小生成树,二分,思路 难度:2
http://www.spoj.com/problems/COMPANYS/en/ 题目要求恰好有k条0类边的最小生成树 每次给0类边的权值加或减某个值delta,直到最小生成树上恰好有k条边为0,此 ...
- hdu4253 Two Famous Companies --- 二分+MST
给n个点.m条边的图.每条边要么属于a公司,要么属于b公司.要求一颗最小生成树,条件是当中属于a公司的边数为k. 这题做法非常巧妙. 要求最小生成树,但有一定限制,搜索.贪心显然都不正确. 要是能找到 ...
- HDOJ 4253 Two Famous Companies 二分+MST
题目意思:给出n个点,m条边,边分为两种,一种是A公司的,一种是B公司的.边上有权值, 问用n-1条边把n个点连起来的最小费用是多少,其中A公司的边刚好有k条.题目保证有解. 题解:题目意思很简单就是 ...
- 【转】并查集&MST题集
转自:http://blog.csdn.net/shahdza/article/details/7779230 [HDU]1213 How Many Tables 基础并查集★1272 小希的迷宫 基 ...
- June 11th 2017 Week 24th Sunday
I hope I can find the one who is afraid of losing me. 我希望找到一个担心失去我的人. When I was young, sometimes I ...
- June 07th 2017 Week 23rd Wednesday
Failure is the condiment that gives success its flavor. 失败是让成功变美味的调味料. There are kinds of flavors in ...
随机推荐
- Android softkeyboard 和 其他界面关系 softInputMode
转 : http://blog.csdn.net/xww810319/article/details/17397429 and http://blog.csdn.net/harryweasley/ar ...
- Intro to Probabilistic Model
概率论复习 概率(Probability) 频率学派(Frequentist):由大量试验得到的期望频率(致命缺陷:有些事情无法大量试验,例如一封邮件是垃圾邮件的概率,雷达探测的物体是一枚导弹的概率) ...
- 【主席树维护mex】 【SG函数递推】 Problem H. Cups and Beans 2017.8.11
Problem H. Cups and Beans 2017.8.11 原题: There are N cups numbered 0 through N − 1. For each i(1 ≤ i ...
- CryptoZombies学习笔记——Lesson3
第三课就开始深入讲解solidity编程技巧了. chapter1: 智能合约的不变性. 合约一旦部署到以太坊后,就不可更改了,所以从一方面来说,智能合约代码的安全性是如此重要,因为一旦发现你的代码里 ...
- NMAP-主机扫描
1.全面扫描 2.扫描指定段 3.ping扫描 只进行ping操作,十分隐蔽 4.无ping扫描 适用于防火墙禁止ping 5.TCP SYN扫描 6.TCP ACK扫描 7.UDP扫描 8.ICMP ...
- Ext JS 6学习文档–第2章–核心概念
核心概念 在下一章我们会构建一个示例项目,而在这之前,你需要学习一些在 Ext JS 中的核心概念,这有助于你更容易理解示例项目.这一章我们将学习以下知识点: 类系统,创建和扩展类 事件 Ext JS ...
- 《javascript模式--by Stoyan Stefanov》书摘--汇总
<javascript模式--by Stoyan Stefanov>书摘--基本技巧 http://www.cnblogs.com/liubei/p/JavascriptModeLog1. ...
- 深入理解Java对象序列化(转载)
原文地址:http://developer.51cto.com/art/201202/317181.htm 1. 什么是Java对象序列化 Java平台允许我们在内存中创建可复用的Java对象,但一般 ...
- iOS- 利用UIImageView自己整了个不会说话的汤姆猫
1.实现思路 先说说我实现它的主要思路,很简单,主要利用UIImageView连续动画播放,和按钮的点击事件,就可以完成了这么一个简单的不会说话的汤姆猫. 2.实现细节 2.1.加载本地字典里保存的本 ...
- 学习 SQL 语句 - Select(9): 其他
//只要前五条记录 procedure TForm1.Button1Click(Sender: TObject); begin with ADODataSet1 do begin Clos ...