【BZOJ2395】[Balkan 2011]Timeismoney
【BZOJ2395】[Balkan 2011]Timeismoney
题面
题解
如果我们只有一个条件要满足的话直接最小生成树就可以了,但是现在我们有两维啊。。。
我们将每个方法的费用和时间看作一个二维坐标\((x,y)\)
则我们要求\(x\centerdot y=k\)最小即要求反比例函数\(y=\frac kx\)的图像离坐标轴最近。
那么我们怎么求呢?分下面三步:
- \(Step1\)
分别求出离\(y,x\)轴最近的点,这个通过直接最小生成树一维排序可以求出。
- \(Step2\)
现在我们的情况是这样的:

\(A\),\(B\)是我们刚才固定的,现在我们需要找到一个点\(C\),使\(C\)在\(AB\)左侧且离\(AB\)最远。
这个怎么办呢?
其实就是让\(S_{\triangle ABC}\)的面积最大。
因为有
\vec {AC}=(C.x-A.x,C.y-A.y)
\]
且有\(S_{\triangle ABC}=\frac {\vec{AB}*\vec{AC}}2\)(但是这个面积是有向的且为负,所以要使这两个向量乘起来最小)
所以我们要最小化:
=(B.x-A.x)*(C.y-A.y)-(B.y-A.y)*(C.x-A.x)\\
=(B.x-A.x)*C.y+(A.y-B.y)*C.x+...
\]
因为我懒后面部分是常数,所以省略了。
那么我直接将改边权为\((B.x-A.x)y[i]+(A.y-B.y)x[i]\),做最小生成树即可。
- \(Step3\)
现在找到了\(C\),递归处理\((A,C)\)、\((C,B)\)即可。
终止条件\(\vec {BA} * \vec{CA}\geq0\),说明此时\(C\)已经跑到\(AB\)右侧去了。
代码
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
const int MAX_N = 205;
const int MAX_M = 1e4 + 5;
struct Point { int x, y; } ;
Point ans = {(int)1e9, (int)1e9};
Point operator - (const Point &l, const Point &r) { return (Point){l.x - r.x, l.y - r.y}; }
int cross(const Point &l, const Point &r) { return l.x * r.y - l.y * r.x; }
int N, M, pa[MAX_N], rnk[MAX_N];
int getf(int x) { return pa[x] == x ? x : pa[x] = getf(pa[x]); }
inline void unite(int x, int y) {
x = getf(x), y = getf(y);
if (rnk[x] == rnk[y]) pa[x] = y, ++rnk[y];
else (rnk[x] < rnk[y]) ? (pa[x] = y) : (pa[y] = x);
}
struct Edge { int u, v, c, t, w; } e[MAX_M];
inline bool operator < (const Edge &l, const Edge &r) { return l.w < r.w; }
#define RG register
inline Point kruskal() {
Point res = (Point){0, 0};
int tot = 0;
for (RG int i = 1; i <= N; ++i) pa[i] = i, rnk[i] = 1;
sort(&e[1], &e[M + 1]);
for (RG int i = 1; i <= M; ++i) {
int u = getf(e[i].u), v = getf(e[i].v);
if (u != v) unite(u, v), res.x += e[i].c, res.y += e[i].t, ++tot;
if (tot == N - 1) break;
}
long long Ans = 1ll * ans.x * ans.y, now = 1ll * res.x * res.y;
if (Ans > now || (Ans == now && res.x < ans.x)) ans = res;
return res;
}
void Div(const Point &A, const Point &B) {
for (RG int i = 1; i <= M; ++i) e[i].w = e[i].t * (B.x - A.x) + e[i].c * (A.y - B.y);
Point C = kruskal();
if (cross(B - A, C - A) >= 0) return ;
Div(A, C); Div(C, B);
}
int main() {
#ifndef ONLINE_JUDGE
freopen("cpp.in", "r", stdin);
#endif
scanf("%d%d", &N, &M);
for (RG int i = 1; i <= M; i++) scanf("%d%d%d%d", &e[i].u, &e[i].v, &e[i].c, &e[i].t);
for (RG int i = 1; i <= M; i++) ++e[i].u, ++e[i].v, e[i].w = e[i].c;
Point A = kruskal();
for (RG int i = 1; i <= M; i++) e[i].w = e[i].t;
Point B = kruskal();
Div(A, B);
printf("%d %d\n", ans.x, ans.y);
return 0;
}
为什么标签有个凸包呢?因为你满足要求的决策点肯定在凸包上啊
【BZOJ2395】[Balkan 2011]Timeismoney的更多相关文章
- BZOJ2395:[Balkan 2011]Timeismoney——题解
https://www.lydsy.com/JudgeOnline/problem.php?id=2395 有n个城市(编号从0..n-1),m条公路(双向的),从中选择n-1条边,使得任意的两个城市 ...
- bzoj2395: [Balkan 2011]Timeismoney
Description 有n个城市(编号从0..n-1),m条公路(双向的),从中选择n-1条边,使得任意的两个城市能够连通,一条边需要的c的费用和t的时间,定义一个方案的权值v=n-1条边 ...
- BZOJ 2395 [Balkan 2011]Timeismoney(最小乘积生成树)
[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=2395 [题目大意] 给出一张无向图,每条边上有a,b两个值,求生成树, 使得suma* ...
- 【最小乘积生成树】bzoj2395[Balkan 2011]Timeismoney
设每个点有x,y两个权值,求一棵生成树,使得sigma(x[i])*sigma(y[i])最小. 设每棵生成树为坐标系上的一个点,sigma(x[i])为横坐标,sigma(y[i])为纵坐标.则问题 ...
- 【BZOJ2395】【Balkan 2011】Timeismoney 最小乘积生成树
链接: #include <stdio.h> int main() { puts("转载请注明出处[辗转山河弋流歌 by 空灰冰魂]谢谢"); puts("网 ...
- BZOJ2395 [Balkan 2011]Timeismoney 【最小乘积生成树】
题目链接 BZOJ2395 题意:无向图中每条边有两种权值,定义一个生成树的权值为两种权值各自的和的积 求权值最小的生成树 题解 如果我们将一个生成树的权值看做坐标,那么每一个生成树就对应一个二维平面 ...
- 【BZOJ】2395: [Balkan 2011]Timeismoney
题解 最小乘积生成树! 我们把,x的总和和y的总和作为x坐标和y左边,画在坐标系上 我们选择两个初始点,一个是最靠近y轴的A,也就是x总和最小,一个是最靠近x轴的B,也就是y总和最小 连接两条直线,在 ...
- bzoj 2395: [Balkan 2011]Timeismoney【计算几何+最小生成树】
妙啊,是一个逼近(?)的做法 把两个值最为平面上的点坐标,然后答案也是一个点. 首先求出可能是答案的点xy分别是按照c和t排序做最小生成树的答案,然后考虑比这两个点的答案小的答案,一定在xy连线靠近原 ...
- bzoj2395[Balkan 2011]Timeismoney最小乘积生成树
所谓最小乘积生成树,即对于一个无向连通图的每一条边均有两个权值xi,yi,在图中找一颗生成树,使得Σxi*Σyi取最小值. 直接处理问题较为棘手,但每条边的权值可以描述为一个二元组(xi,yi),这也 ...
随机推荐
- 四级菜单实现(Python)
menu_dict = { '山东' : { '青岛' : { '四方':{'兴隆路','平安路','杭州路'}, '黄岛':{}, '崂山':{} }, '济南' : { '历城':{}, '槐荫' ...
- Python - if-else 的多种简洁写法
本博客原文来自:http://www.cnblogs.com/xiexiaoxiao/p/7772441.html,对原作者表示感谢,此处个人转载. 1. 常用 if ... else写法 # 语法 ...
- ethereumjs/merkle-patricia-tree-1-简介
https://github.com/ethereumjs/merkle-patricia-tree SYNOPSIS概要 This is an implementation of the modif ...
- leetcode 121. Best Time to Buy and Sell Stock 、122.Best Time to Buy and Sell Stock II 、309. Best Time to Buy and Sell Stock with Cooldown
121. Best Time to Buy and Sell Stock 题目的要求是只买卖一次,买的价格越低,卖的价格越高,肯定收益就越大 遍历整个数组,维护一个当前位置之前最低的买入价格,然后每次 ...
- Ubuntu16.04配置单机版Zookeeper和Kafka
1. 配置zookeeper单机模式 选择的是zookeeper-3.4.10版本,官网下载链接:http://mirrors.hust.edu.cn/apache/zookeeper/stable/ ...
- 服务器监控zabbix
nagios服务器安装:http://www.jb51.net/article/79496.htm默认端口12489 nagios +ndo2db+mysqlhttps://www.cnblogs.c ...
- SpringMVC中controller的几种返回值
String :跳转到对应的返回值中. return “/index”: ModelAndView: 控制页面跳转方式: 1. ModelAndView modelAndView = new Mode ...
- 纯 js 实现上传文件支持拖拽
开发「bufpay.com 个人即时到账收款平台」 后台需要支持开发者的微信和支付宝二维码上传. <p> <button class="btn btn-primary&qu ...
- eclipse手动安装alibaba代码规范插件+取消阿里编码规约插件扫描出来的警告及错误
如果你的开发环境无法访问外网,那么手动安装阿里巴巴的代码规范插件是一个不错的选择.另外,很多教程说该插件需要jdk1.8以上,我试了一下jdk1.7也是可以运行的,更低的版本就不知道了,貌似jdk1. ...
- Linux基础-1.Linux命令及获取帮助
1.Linux命令的格式 1)了解Linux命令的语法格式: 命令 [选项] [参数] 2)掌握命令格式中命令.选项.参数的具体的含义 a)命令:告诉Linux(UNIX)操作系统做(执行)什么 b) ...