@bzoj - 2395@ [Balkan 2011]Timeismoney
@description@
有n个城市(编号从0..n-1),m条公路(双向的),从中选择n-1条边,使得任意的两个城市能够连通,一条边需要的c的费用和t的时间,定义一个方案的权值 v = (n-1条边的费用和)*(n-1条边的时间和),你的任务是求一个方案使得v最小。
Input
第一行两个整数n,m,接下来每行四个整数a,b,c,t,表示有一条公路从城市a到城市b需要t时间和费用c
Output
仅一行两个整数sumc,sumt,(sumc表示使得v最小时的费用和,sumc表示最小的时间和) 如果存在多个解使得sumc*sumt相等,输出sumc最小的
Sample Input
5 7
0 1 161 79
0 2 161 15
0 3 13 153
1 4 142 183
2 4 236 80
3 4 40 241
2 1 65 92
Sample Output
279 501
HINT
【数据规模】
1<=N<=200, 1<=m<=10000, 0<=a,b<=n-1, 0<=t,c<=255。
有5%的数据m=n-1
有40%的数据有t=c
对于100%的数据如上所述
@solution@
非常经典的题.jpg。
假如将 (sumc, sumt) 看成一个坐标,那么一个可行生成树方案对应了坐标系中的一个点。
可以发现:只有下凸包上的点才可能成为答案。
如果不在下凸包上,那么可以作原点到该点的直线,它与凸包的交点显然更优。
同时,一条线段肯定取两个端点得到的乘积最小(写出表达式发现是二次函数)。
因为三点共线肯定不优,所以凸包上的斜率互不相同且递减。因此,凸包上的点最多只有 \(O(\sqrt{N*\max\{c, t\}})\) 个点。
我们只需要尝试找出凸包上的点并更新答案即可。
考虑两个必定在凸包内的点 A(minx, y) 与 B(x, miny)(不可能找到更大的凸包严格包含这两个点)。
如果忽视掉下凸包中斜率为正的部分(这部分肯定不优),这两个点就是凸包上的点横纵坐标的边界。
我们根据直线 AB,找该直线在凸包上对应的切线,就可以又找到一个新的凸包上的点。
其实就是距离 AB 最远的点 C。距离最远可以转成 ABC 的面积最大,然后可以写出叉积。
根据叉积式子再做一遍最大生成树(注意是最大)就可以找到 C 了。
然后分治 AC, CB 即可。
时间复杂度的一个上界为 \(O(\sqrt{N*\max\{c, t\}}*M\log M)\)。
@accepted code@
#include <cstdio>
#include <algorithm>
using namespace std;
const int MAXN = 200;
const int MAXM = 10000;
const int INF = int(1E9);
typedef long long ll;
int n, m;
struct point{
int c, t; ll k;
point(int _c=0, int _t=0) : c(_c), t(_t), k(1LL*_c*_t) {}
friend point operator + (point a, point b) {
return point(a.c + b.c, a.t + b.t);
}
}ans(INF, INF);
void update(point p) {
if( p.k < ans.k || (p.k == ans.k && p.c < ans.c) )
ans = p;
}
int a, b;
struct edge{
int u, v; point p;
ll get() {return 1LL*a*p.c + 1LL*b*p.t;}
friend bool operator < (edge a, edge b) {
return a.get() < b.get();
}
}e[MAXM + 5];
int fa[MAXN + 5];
int find(int x) {
return fa[x] = (fa[x] == x ? x : find(fa[x]));
}
point get() {
for(int i=1;i<=n;i++) fa[i] = i;
sort(e + 1, e + m + 1);
point ret(0, 0);
for(int i=1;i<=m;i++) {
int fu = find(e[i].u), fv = find(e[i].v);
if( fu != fv ) {
ret = ret + e[i].p;
fa[fu] = fv;
}
}
return ret;
}
void solve(point A, point B) {
a = (A.t - B.t), b = (B.c - A.c);
point C = get();
if( a*C.c + b*C.t + (B.t - A.t)*B.c + (A.c - B.c)*B.t >= 0 )
return ;
update(C), solve(A, C), solve(C, B);
}
int main() {
scanf("%d%d", &n, &m);
for(int i=1;i<=m;i++) {
scanf("%d%d%d%d", &e[i].u, &e[i].v, &e[i].p.c, &e[i].p.t);
e[i].u++, e[i].v++;
}
a = 1, b = 0; point A = get(); update(A);
a = 0, b = 1; point B = get(); update(B);
solve(A, B);
printf("%d %d\n", ans.c, ans.t);
}
@details@
其实这个模型之所以经典,是因为它的可迁移性很强。
比如给你整一个下一次最小乘积最短路,最小乘积最小割之类的。
另外,我们 01 分数规划 + 最小生成树,尽管平时用的是二分,其实也可以采用几何方法来做。
但是复杂度就很玄妙了。
@bzoj - 2395@ [Balkan 2011]Timeismoney的更多相关文章
- bzoj 2395 [Balkan 2011]Timeismoney——最小乘积生成树
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2395 如果把 \( \sum t \) 作为 x 坐标,\( \sum c \) 作为 y ...
- BZOJ 2395 [Balkan 2011]Timeismoney(最小乘积生成树)
[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=2395 [题目大意] 给出一张无向图,每条边上有a,b两个值,求生成树, 使得suma* ...
- bzoj 2395: [Balkan 2011]Timeismoney【计算几何+最小生成树】
妙啊,是一个逼近(?)的做法 把两个值最为平面上的点坐标,然后答案也是一个点. 首先求出可能是答案的点xy分别是按照c和t排序做最小生成树的答案,然后考虑比这两个点的答案小的答案,一定在xy连线靠近原 ...
- 【BZOJ】2395: [Balkan 2011]Timeismoney
题解 最小乘积生成树! 我们把,x的总和和y的总和作为x坐标和y左边,画在坐标系上 我们选择两个初始点,一个是最靠近y轴的A,也就是x总和最小,一个是最靠近x轴的B,也就是y总和最小 连接两条直线,在 ...
- BZOJ 2395 [Balkan 2011]Time is money
题面 题解 将\(\sum_i c_i\)和\(\sum_i t_i\)分别看做分别看做\(x\)和\(y\),投射到平面直角坐标系中,于是就是找\(xy\)最小的点 于是可以先找出\(x\)最小的点 ...
- 【BZOJ2395】[Balkan 2011]Timeismoney
[BZOJ2395][Balkan 2011]Timeismoney 题面 \(darkbzoj\) 题解 如果我们只有一个条件要满足的话直接最小生成树就可以了,但是现在我们有两维啊... 我们将每个 ...
- bzoj2395: [Balkan 2011]Timeismoney
Description 有n个城市(编号从0..n-1),m条公路(双向的),从中选择n-1条边,使得任意的两个城市能够连通,一条边需要的c的费用和t的时间,定义一个方案的权值v=n-1条边 ...
- Bzoj2395: [Balkan 2011]Timeismoney(最小乘积生成树)
问题描述 每条边两个权值 \(x,y\),求一棵 \((\sum x) \times (\sum y)\) 最小的生成树 Sol 把每一棵生成树的权值 \(\sum x\) 和 \(\sum y\) ...
- BZOJ2395:[Balkan 2011]Timeismoney——题解
https://www.lydsy.com/JudgeOnline/problem.php?id=2395 有n个城市(编号从0..n-1),m条公路(双向的),从中选择n-1条边,使得任意的两个城市 ...
随机推荐
- line-height:150%/1.5em与line-height:1.5的区别
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- 读书笔记--Head First 面向对象分析与设计 目录
1.良好应用程序的基石 2.收集需求 3.需求变更 4.分析 5.良好的设计=灵活的软件 6.解决大问题 7.架构 8.设计原则 9.迭代与测试 10.OOA&D 的生命周期 附录1 附录2
- Excel 表格中根据某一列的值从另一个xls文件的对应sheet中查找包含其中一列的内容(有点拗口)
=VLOOKUP(C3&"*",INDIRECT("'[2008-2016年三地商务明细表.xls]"&L3&"年北京'!$D ...
- java.lang.NoSuchMethodError: org.apache.commons.io.FileUtils.copyInputStreamToFile(Ljava/io/InputStream;Ljava/io/File;)V
昨天用的好好的,今天就不行了 也懒得搞 具体原因就是引用的问题 找了个能用的pom 直接贴过去完事儿
- Ubuntu 安装 RabbitMQ 和PHP扩展 - CSDN博客
1.ubuntu16.04中安装RabbitMQ 1).首先必须要有Erlang环境支持 安装之前要装一些必要的库: sudo apt-get install build-essential sud ...
- 微服务开源生态报告 No.7
「微服务开源生态报告」,汇集各个开源项目近期的社区动态,帮助开发者们更高效的了解到各开源项目的最新进展. 社区动态包括,但不限于:版本发布.人员动态.项目动态和规划.培训和活动. 非常欢迎国内其他微服 ...
- (二)SpringBoot功能
web开发 spring boot web开发非常的简单,其中包括常用的json输出.filters.property.log等 json 接口开发 在以前的spring 开发的时候需要我们提供jso ...
- php语言的核心知识点
PHP:脚本语言,网站建设,服务器端运行PHP定义:一种服务器端的 HTML 脚本/编程语言,是一种简单的.面向对象的.解释型的.健壮的.安全的.性能非常之高的.独立于架构的.可移植的.动态的脚本语言 ...
- 多线程 多进程 协程 Queue(爬虫代码)
快速理解多进程与多线程以及协程的使用场合和特点 首先我们来了解下python中的进程,线程以及协程! 从计算机硬件角度: 计算机的核心是CPU,承担了所有的计算任务.一个CPU,在一个时间切片里只能运 ...
- Quarz框架学习
参考博客:https://www.cnblogs.com/zhanghaoliang/p/7886110.html