Luogu5540 最小乘积生成树

题目链接:洛谷

题目描述:对于一个\(n\)个点\(m\)条边的无向连通图,每条边有两个边权\(a_i,b_i\),求使\((\sum a_i)\times (\sum b_i)\)最小的生成树。

数据范围:\(n\le 200,m\le 10000,a_i,b_i\le 255\)

这题是一道非常妙的计算几何题目。

我们对于每个生成树,用\((\sum a_i,\sum b_i)\)这个二维平面上的点来表示它,那么就是求所有点中横坐标乘纵坐标的最小值。

画画图就可以发现,答案只有可能在下凸包上,为什么呢?

因为如果\(C\)在线段\(AB\)上方,其中\(x_Ay_A=x_By_B\),因为反比例函数下凸,所以\(x_Cy_C>x_Ay_A\)。

但是生成树可能有很多个,怎么得到下凸包上的点呢?

Step1 求最靠近\(x,y\)轴的两个点\(A,B\)

为什么呢?因为\(A,B\)两个点必定在下凸包上面。令\(w_i=a_i\)或\(b_i\)用最小生成树求\(A,B\)。

Step2 求\(C\)在直线\(AB\)下方且\(S_{\Delta ABC}\)最大

为什么呢?因为\(C\)点必定在下凸包上面,否则它不是最大的点。我们发现

\[\begin{aligned}
-\frac{1}{2}S_{\Delta ABC}&=\overrightarrow{AB}\times \overrightarrow{AC} \\
&=(x_B-x_A)(y_C-y_A)-(y_B-y_A)(x_C-x_A) \\
&=((x_A-x_B)y_A-(y_A-y_B)x_A)+(x_B-x_A)y_C-(y_B-y_A)x_C
\end{aligned}
\]

令\(w_i=(x_B-x_A)b_i-(y_B-y_A)a_i\)就会得到\(C\)

Step3 将(A,C)和(C,B)代入Step2递归

这样就可以求出下凸包上所有的点。那什么时候终止递归呢?当然就是\(C\)不存在,或者说求出的\(C\)在\(AB\)上方。

时间复杂度为\(O(km\log m)\),其中\(k\)为下凸包上点的个数,在随机数据下不会很大。

#include<bits/stdc++.h>
#define Rint register int
using namespace std;
typedef long long LL;
const int N = 10003;
int n, m, a[N], b[N], fa[N];
struct Point {
int x, y;
inline Point(int _x = 0, int _y = 0): x(_x), y(_y){}
inline Point operator - (const Point &o) const {return (Point){x - o.x, y - o.y};}
} A, B, ans(1e9, 1e9);
inline LL cross(Point a, Point b){return (LL) a.x * b.y - (LL) b.x * a.y;}
struct Edge {
int u, v, w, id;
inline bool operator < (const Edge &o) const {return w < o.w;}
} e[N];
inline int getfa(int x){return x == fa[x] ? x : fa[x] = getfa(fa[x]);}
inline Point Kruskal(){
Point res; sort(e + 1, e + m + 1);
for(Rint i = 1;i <= n;i ++) fa[i] = i;
for(Rint i = 1, p = 1;i <= m && p < n;i ++){
int u = getfa(e[i].u), v = getfa(e[i].v);
if(u != v){fa[u] = v; ++ p; res.x += a[e[i].id]; res.y += b[e[i].id];}
}
LL Ans = (LL) ans.x * ans.y, Res = (LL) res.x * res.y;
if(Ans > Res || Ans == Res && ans.x > res.x) ans = res;
return res;
}
inline void solve(Point A, Point B){
for(Rint i = 1;i <= m;i ++) e[i].w = (A.y - B.y) * a[e[i].id] - (A.x - B.x) * b[e[i].id]; Point C = Kruskal();
if(cross(B - A, C - A) >= 0) return;
solve(A, C); solve(C, B);
}
int main(){
scanf("%d%d", &n, &m);
for(Rint i = 1;i <= m;i ++) scanf("%d%d%d%d", &e[i].u, &e[i].v, a + i, b + i), ++ e[i].u, ++ e[i].v, e[i].id = i;
for(Rint i = 1;i <= m;i ++) e[i].w = a[e[i].id]; Point A = Kruskal();
for(Rint i = 1;i <= m;i ++) e[i].w = b[e[i].id]; Point B = Kruskal();
solve(A, B); printf("%d %d", ans.x, ans.y);
}

Luogu5540 最小乘积生成树的更多相关文章

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

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

  2. HDU5697 刷题计划 dp+最小乘积生成树

    分析:就是不断递归寻找靠近边界的最优解 学习博客(必须先看这个): 1:http://www.cnblogs.com/autsky-jadek/p/3959446.html 2:http://blog ...

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

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

  4. 【算法】最小乘积生成树 & 最小乘积匹配 (HNOI2014画框)

    今天考试的时候果然题目太难于是我就放弃了……转而学习了一下最小乘积生成树. 最小乘积生成树定义: (摘自网上一篇博文). 我们主要解决的问题就是当k = 2时,如何获得最小的权值乘积.我们注意到一张图 ...

  5. Bzoj2395: [Balkan 2011]Timeismoney(最小乘积生成树)

    问题描述 每条边两个权值 \(x,y\),求一棵 \((\sum x) \times (\sum y)\) 最小的生成树 Sol 把每一棵生成树的权值 \(\sum x\) 和 \(\sum y\) ...

  6. bzoj2395 [Balkan 2011]Timeismoney(最小乘积生成树+计算几何)

    题意 每条边有两个权值\(c,t\),请求出一颗生成树,使得\(\sum c\times \sum t\)最小 题解 为什么生成树会和计算几何扯上关系-- 对于每棵树,设\(x=c,y=t\),我们可 ...

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

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

  8. P5540-[BalkanOI2011]timeismoney|最小乘积生成树【最小生成树,凸壳】

    正题 题目链接:https://www.luogu.com.cn/problem/P5540 题目大意 给出\(n\)个点\(m\)条边边权是一个二元组\((a_i,b_i)\),求出一棵生成树最小化 ...

  9. bzoj 2395 [Balkan 2011]Timeismoney——最小乘积生成树

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2395 如果把 \( \sum t \) 作为 x 坐标,\( \sum c \) 作为 y ...

随机推荐

  1. Python之特征工程-3

    一.什么是特征工程?其实也是数据处理的一种方式,和前面的原始数据不一样的是,我们在原始数据的基础上面,通过提取有效特征,来预测目标值.而想要更好的去得出结果,包括前面使用的数据处理中数据特征提取,新增 ...

  2. python之基础总结(飞机大战)

    一.学习python有一段时间了,总体上手还是挺好的,但是有些东西还是和Java存在着一定的区别,这里主要是通过学习,然后自己去编写一个案例.从中学习到的一些东西,这里分享出来,如果存在不正确的地方还 ...

  3. IIS发布问题解决

    一. HTTP Error 502.5 - ANCM Out-Of-Process Startup Failure ://安装AspNetCoreModule托管模块后执行1. net stop wa ...

  4. LeetCode每日一练(1-3)

    题目导航 1. 两数之和 2. 两数相加 3. 无重复字符的最长子串 1. 两数之和 给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的 ...

  5. source tree每次push都需要密码的解决方法

    Windows首先可以考虑使用GitHub for Windows,它已经包含了该助手,或者可以下载对应系统的版本:Windows 7.Windows 8.Source 版本,然后解压缩文件并将里面的 ...

  6. Traceback (most recent call last): File "../zubax_chibios/tools/make_boot_descriptor.py", line 251

    出现如下错误: Traceback (most recent call last): File "../zubax_chibios/tools/make_boot_descriptor.py ...

  7. S5PV210 PWM

    定时器PWM输出 原理图 GPD0CON, R/W, Address = 0xE020_00A0 CON, R/W, Address = 0xE250_0008 相关文章:http://blog.cs ...

  8. 【亲测有效】vs2017无法断点

    解决方案: 一:设置为Debug模式 二:[工具]--[选项]--[调试]--[常规],取消打钩[要求源文件与原始版本完全匹配]

  9. Linux日志查看

    Linux日志查看: 1.Last -a 把从何处登入系统的主机名称或IP地址,显示在最后一行.-d 指定记录文件.指定记录文件.将IP地址转换成主机名称.-f <记录文件>  指定记录文 ...

  10. 中文论文-LaTex模板

    \documentclass[10pt,UTF8]{article} \usepackage{ctex} \usepackage{amssymb,amsmath,multicol,titlesec} ...