【BZOJ2395】[Balkan 2011]Timeismoney

题面

\(darkbzoj\)

题解

如果我们只有一个条件要满足的话直接最小生成树就可以了,但是现在我们有两维啊。。。

我们将每个方法的费用和时间看作一个二维坐标\((x,y)\)

则我们要求\(x\centerdot y=k\)最小即要求反比例函数\(y=\frac kx\)的图像离坐标轴最近。

那么我们怎么求呢?分下面三步:

  • \(Step1\)

分别求出离\(y,x\)轴最近的点,这个通过直接最小生成树一维排序可以求出。

  • \(Step2\)

现在我们的情况是这样的:

\(A\),\(B\)是我们刚才固定的,现在我们需要找到一个点\(C\),使\(C\)在\(AB\)左侧且离\(AB\)最远。

这个怎么办呢?

其实就是让\(S_{\triangle ABC}\)的面积最大。

因为有

\[\vec {AB}=(B.x-A.x,B.y-A.y)\\
\vec {AC}=(C.x-A.x,C.y-A.y)
\]

且有\(S_{\triangle ABC}=\frac {\vec{AB}*\vec{AC}}2\)(但是这个面积是有向的且为负,所以要使这两个向量乘起来最小)

所以我们要最小化:

\[\vec{AB}*\vec{AC}\\
=(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的更多相关文章

  1. BZOJ2395:[Balkan 2011]Timeismoney——题解

    https://www.lydsy.com/JudgeOnline/problem.php?id=2395 有n个城市(编号从0..n-1),m条公路(双向的),从中选择n-1条边,使得任意的两个城市 ...

  2. bzoj2395: [Balkan 2011]Timeismoney

    Description      有n个城市(编号从0..n-1),m条公路(双向的),从中选择n-1条边,使得任意的两个城市能够连通,一条边需要的c的费用和t的时间,定义一个方案的权值v=n-1条边 ...

  3. BZOJ 2395 [Balkan 2011]Timeismoney(最小乘积生成树)

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=2395 [题目大意] 给出一张无向图,每条边上有a,b两个值,求生成树, 使得suma* ...

  4. 【最小乘积生成树】bzoj2395[Balkan 2011]Timeismoney

    设每个点有x,y两个权值,求一棵生成树,使得sigma(x[i])*sigma(y[i])最小. 设每棵生成树为坐标系上的一个点,sigma(x[i])为横坐标,sigma(y[i])为纵坐标.则问题 ...

  5. 【BZOJ2395】【Balkan 2011】Timeismoney 最小乘积生成树

    链接: #include <stdio.h> int main() { puts("转载请注明出处[辗转山河弋流歌 by 空灰冰魂]谢谢"); puts("网 ...

  6. BZOJ2395 [Balkan 2011]Timeismoney 【最小乘积生成树】

    题目链接 BZOJ2395 题意:无向图中每条边有两种权值,定义一个生成树的权值为两种权值各自的和的积 求权值最小的生成树 题解 如果我们将一个生成树的权值看做坐标,那么每一个生成树就对应一个二维平面 ...

  7. 【BZOJ】2395: [Balkan 2011]Timeismoney

    题解 最小乘积生成树! 我们把,x的总和和y的总和作为x坐标和y左边,画在坐标系上 我们选择两个初始点,一个是最靠近y轴的A,也就是x总和最小,一个是最靠近x轴的B,也就是y总和最小 连接两条直线,在 ...

  8. bzoj 2395: [Balkan 2011]Timeismoney【计算几何+最小生成树】

    妙啊,是一个逼近(?)的做法 把两个值最为平面上的点坐标,然后答案也是一个点. 首先求出可能是答案的点xy分别是按照c和t排序做最小生成树的答案,然后考虑比这两个点的答案小的答案,一定在xy连线靠近原 ...

  9. bzoj2395[Balkan 2011]Timeismoney最小乘积生成树

    所谓最小乘积生成树,即对于一个无向连通图的每一条边均有两个权值xi,yi,在图中找一颗生成树,使得Σxi*Σyi取最小值. 直接处理问题较为棘手,但每条边的权值可以描述为一个二元组(xi,yi),这也 ...

随机推荐

  1. 深入剖析Swift性能优化

    简介 2014年,苹果公司在WWDC上发布Swift这一新的编程语言.经过几年的发展,Swift已经成为iOS开发语言的“中流砥柱”,Swift提供了非常灵活的高级别特性,例如协议.闭包.泛型等,并且 ...

  2. SHA1WithRSA

    SHA1WithRSA:用SHA算法进行签名,用RSA算法进行加密.   算法说明: 在对进行SHA1算法进行签名后,要求对签名后的数据进行处理,而不是直接进行RSA算法进行加密. 要求把SHA1签名 ...

  3. Kafka TimeoutException: Batch Expired 问题排查

    当前系统中produer配置request.timeout.ms=30000(30秒),但是broker端配置zookeeper.connection.timeout.ms=1000000,kafka ...

  4. 递归根据父ID 找所有子类ID

    function getinfo($pid){ $str = ''; $row = M('user')->where(array('pid'=>$pid))->select(); i ...

  5. PAT——1052. 卖个萌

    萌萌哒表情符号通常由“手”.“眼”.“口”三个主要部分组成.简单起见,我们假设一个表情符号是按下列格式输出的: [左手]([左眼][口][右眼])[右手] 现给出可选用的符号集合,请你按用户的要求输出 ...

  6. 快速排序及STL中的sort算法

    快速排序基本思想是,对待排序序列进行划分(Partition),一次划分,选择一个元素作为枢轴,然后将所有比枢轴小的元素放到枢轴的左边,将比枢轴大的元素放到枢轴的右边.然后对该枢轴划分的左右子序列分别 ...

  7. 配置tomcat的用户名和密码

    <role rolename="manager-gui"/> <role rolename="manager-script"/> < ...

  8. C# 反射 Reflection Assembly

    本章节带来的是反射,反射反射程序员的快乐. 一.什么叫反射 反射:是.net Framework提供给的一个方面metadata的帮助类,可以获取信息并且使用 反射的有点:动态 反射的缺点:1:稍微麻 ...

  9. js正则表达式——元字符

    元字符 具有特殊意义的元字符 \d 匹配0-9的数字,相当于[0-9] \D 匹配除了0-9的任意字符 \w 匹配0-9.a-z.A-Z._ 的数字或字符,相当于[0-9a-zA-Z_] \W 匹配不 ...

  10. Linux启动流程(CentOS6)

    内核级别: (POST)BIOS加电自检-->(Boot Sequence)从BIOS中读取启动顺序-->读取MBR中的bootloader-->加载内核-->读取伪根--&g ...