【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. Ubuntu root 密码忘记-恢复

    @Ubuntu root 密码忘记-恢复 2012-04-27 11:09:22 方法一: 如果用户具有sudo权限,那么直接可以运行如下命令: #sudo su root #passwd #更改密码 ...

  2. Web项目打成war包部署Tomcat时运行startup.bat直接闪退部署失败解决方案

    即上篇通过将web项目打成war包部署到Tomcat服务器,解决mysql问题后,又出现了新问题,真是一波三折,所以将解决过程分享给大家,希望能帮助到小伙伴们~ 将打好的war包拷贝到Tomcat的w ...

  3. Qt中QScrollArea类的简单使用心得

           平台:windows 64位        Qt版本:5.5.1 MinGW 32bit 根据自己目前的需求简单说下怎么在QScrollArea滚动窗口中实现多个控件的滚动显示,先看看最 ...

  4. HDU 1198 Farm Irrigation(并查集,自己构造连通条件或者dfs)

    Farm Irrigation Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)T ...

  5. 初始化mysql数据库 /usr/bin/mysql_install_db执行时报错

    错误描述: FATAL ERROR: please install the following Perl modules before executing /usr/bin/mysql_install ...

  6. 在 Oracle Linux 6.5 上安装 Oracle 11g 单实例数据库

    Checking the Hardware Requirements 系统必须满足下面最小的硬件要求 Memory Requirements Minimum: 1 GB of RAMRecommend ...

  7. Python %操作符 字符串格式化

    %操作符(字符串格式化,string formatting),说明如下: %[(name)][flags][width].[precision]typecode (name)为命名 flags可以有+ ...

  8. File、Paths和Files类的使用详解

    Paths:通过get()方法返回一个Path对象,Path用于表示文件路径和文件. Files:提供了大量处理文件的方法,例如文件复制.读取.写入,获取文件属性.快捷遍历文件目录等..... Fil ...

  9. 小白的Unity5之路(一)

    Player移动: public float speed = 6f; Vector3 movement; Rigidbody playerRididbody; void FixedUpdate () ...

  10. 使用VMware安装CentOS7

    以前一直用的CentOS6,这次搭建一套CentOS7. 感觉和6还是有一些差异,在这边记录下. 一.选择典型(推荐): 二.选择安装程序光盘映像文件: 网上有几个版本,mini版,DVD版,不过mi ...