【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. SEO搜索引擎优化(转)

    (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.s ...

  2. 联想Thinkpad 遇到双系统 uefi Ubuntu无法进入的引导问题解决方案

    最近因为许多课程设计的需要,安装了Ubuntu双系统,但是一开始遇到了安装好了以后无法进入的问题,后来弄好后手残又把引导项给删了又要弄回去,反反复复很多次,网上的很多经验都十分过时,要么对最新的uef ...

  3. RedisClient的安装及基本使用

    管理redis的可视化客户端目前较流行的有三个:Redis Client ; Redis Desktop Manager ; Redis Studio. 这里目前给大家介绍Redis Client 的 ...

  4. webview综述

    nWebView 是webkit最核心的一个view,WebView管理WebFrameView和WebFrame之间的交互,一个WebView对象绑定一个window,并且要求MainFrame加载 ...

  5. Django中模型(三)

    Django中模型(三) 四.模型成员 1.类属性 objects:是Manager类的一个对象,作用是与数据库进行交互. 定义模型类时,没有定义管理器,则默认创建名为objects的管理器. 2.自 ...

  6. 【转】Linux下RabbitMQ服务器搭建(单实例)

    阅读目录 系统环境 安装步骤 注意事项 参考资料 回到顶部 系统环境 操作系统:CentOS6.9 erlang:OTP 19.3 rabbitmq:rabbitmq-server 3.6.12 回到 ...

  7. Java 读取properties

    package Db; import java.io.InputStream; import java.util.Properties; import java.io.BufferedReader; ...

  8. 【hdu 3177 Crixalis's Equipment】 题解

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3177 \(describe\): 有一个山洞,山洞的容积最大为\(v\).现在你有\(n\)个物品,这 ...

  9. Epoll为我们带来了什么

    libevent中用到的,epoll是Linux下多路复用IO接口select/poll的增强版本.网上找到的介绍资料,无法标明来源. Q:网络服务器的瓶颈在哪? A:IO效率. 在大家苦苦的为在线人 ...

  10. Office365学习笔记—Lookup类型加载条目过多解决方案

    1,随着接触的项目越来越多,遇到的各种奇葩的问题也越来越多,不得不说,SharePoint是个好东西,提高了开发效率,简化了很多基础的功能.但是令人头疼的问题是,当你想做个稍微复杂点的功能,就不得不研 ...