题目链接

BZOJ2395

题意:无向图中每条边有两种权值,定义一个生成树的权值为两种权值各自的和的积

求权值最小的生成树

题解

如果我们将一个生成树的权值看做坐标,那么每一个生成树就对应一个二维平面上的坐标

在同一个反比例函数图像上的点权值相同,反比例函数\(xy\)越小的点越贴近坐标轴

所以答案一定在下凸包上

我们就递归查找这样的点

我们先分别将两种权值作为指标求出\(A\)和\(B\)两个点,分别是\(x\)最小的点和\(y\)最小的点,即为下凸包的一个边界

我们找到位于\(AB\)左下角最远的点\(C\)

为了方便,由于底\(|AB|\)确定,\(S\triangle ABC\)越大,距离越远

那么\(C\)满足最小化

\[\overrightarrow{CA} \times \overrightarrow{CB}
\]

展开叉乘,去掉常数项,可得

\[(y_A - y_B) * x_C + (x_B - x_A) * y_C
\]

将其作为新的边权,跑kruskal即可得到新的点\(C\)

然后将\(AC\)和\(CB\)分别作为底继续递归下去,直至找不到点为止

过程中更新答案,显然一定会经过下凸包上所有点

复杂度\(O(可以被卡)\),只需要构造所有点都在下凸包上,就会退化为\(O(生成树个数)\)

不知道能不能构造出来

为了方便理解,再盗一张图

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define LL long long int
#define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define BUG(s,n) for (int i = 1; i <= (n); i++) cout<<s[i]<<' '; puts("");
using namespace std;
const int maxn = 205,maxm = 10005,INF = 0x3fffffff;
inline int read(){
int out = 0,flag = 1; char c = getchar();
while (c < 48 || c > 57){if (c == '-') flag = -1; c = getchar();}
while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();}
return out * flag;
}
int n,m,pre[maxn];
struct EDGE{int a,b,x,y,v;}e[maxm];
struct point{int x,y;}ans;
inline int find(int u){return u == pre[u] ? u : pre[u] = find(pre[u]);}
inline bool operator <(const EDGE& a,const EDGE& b){
return a.v < b.v;
}
inline point operator -(const point& a,const point& b){
return (point){a.x - b.x,a.y - b.y};
}
inline LL operator *(const point& a,const point& b){
return 1ll * a.x * b.y - 1ll * a.y * b.x;
}
inline bool operator <(const point& a,const point& b){
return 1ll * a.x * a.y == 1ll * b.x * b.y ? a.x < b.x : 1ll * a.x * a.y < 1ll * b.x * b.y;
}
point kruskal(){
sort(e + 1,e + 1 + m);
REP(i,n) pre[i] = i;
point re; int cnt = n,u,v; re.x = re.y = 0;
for (int i = 1; i <= m && cnt > 1; i++){
u = find(e[i].a); v = find(e[i].b);
if (u != v){
pre[u] = v;
cnt--;
re.x += e[i].x;
re.y += e[i].y;
}
}
if (re < ans) ans = re;
return re;
}
void solve(point A,point B){
REP(i,m) e[i].v = (A.y - B.y) * e[i].x + (B.x - A.x) * e[i].y;
point C = kruskal();
if ((C - A) * (B - A) <= 0) return;
solve(A,C); solve(C,B);
}
int main(){
n = read(); m = read(); ans.x = ans.y = INF;
REP(i,m){
e[i].a = read() + 1,e[i].b = read() + 1;
e[i].x = read(),e[i].y = read();
}
REP(i,m) e[i].v = e[i].x;
point A = kruskal();
REP(i,m) e[i].v = e[i].y;
point B = kruskal();
solve(A,B);
printf("%d %d\n",ans.x,ans.y);
return 0;
}

BZOJ2395 [Balkan 2011]Timeismoney 【最小乘积生成树】的更多相关文章

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

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

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

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

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

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

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

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

  5. bzoj2395: [Balkan 2011]Timeismoney

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

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

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

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

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

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

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

  9. 洛谷 P5540 - [BalkanOI2011] timeismoney | 最小乘积生成树(最小生成树)

    洛谷题面传送门 大概是一个比较 trivial 的小 trick?学过了就不要忘了哦( 莫名奇妙地想到了 yyq 的"hot tea 不常有,做过了就不能再错过了" 首先看到这种二 ...

随机推荐

  1. frombuffer的用法

    函数原型为:numpy.ma.frombuffer(buffer, dtype=float, count=-1, offset=0) import numpy s = 'hello world' pr ...

  2. java编程基础——栈压入和弹出序列

    题目描述 输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序.假设压入栈的所有数字均不相等.例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压 ...

  3. 2018年ElasticSearch6.2.2教程ELK搭建日志采集分析系统(教程详情)

    章节一  2018年 ELK课程计划和效果演示1.课程安排和效果演示    简介:课程介绍和主要知识点说明,ES搜索接口演示,部署的ELK项目演示    es: localhost:9200    k ...

  4. java中 二进制 八进制 十六进制 十进制 相互转换 最简方法

    package com.swift; import java.util.Scanner; public class Hex2Decimal { public static void main(Stri ...

  5. 【搜索】【入门】洛谷P1036 选数

    题目描述 已知 n个整数x1​,x2​,…,xn​,以及1个整数k(k<n).从nn个整数中任选kk个整数相加,可分别得到一系列的和. 例如当n=4,k=3,4个整数分别为3,7,12,19时, ...

  6. cf540D. Bad Luck Island(概率dp)

    题意 岛上有三个物种:剪刀$s$.石头$r$.布$p$ 其中剪刀能干掉布,布能干掉石头,石头能干掉剪刀 每天会从这三个物种中发生一场战争(也就是说其中的一个会被干掉) 问最后仅有$s/r/p$物种生存 ...

  7. Tame Me【驯服我】

    Tame Me “Good morning,” said the fox. 早上好,狐狸说 “Good morming,” the little prince responded politely,a ...

  8. A1082 Read Number in Chinese (25)(25 分)

    A1082 Read Number in Chinese (25)(25 分) Given an integer with no more than 9 digits, you are suppose ...

  9. [GDOI2016][树链剖分+主席树]疯狂动物城

    题面 Description Nick 是只在动物城以坑蒙拐骗为生的狐狸,儿时受到偏见的伤害,放弃了自己的理想.他被兔子 Judy 设下圈套,被迫与她合作查案,而卷入意想不到的阴谋,历尽艰险后成为搭档 ...

  10. P1880 [NOI1995]石子合并【区间DP】

    题目描述 在一个圆形操场的四周摆放N堆石子,现要将石子有次序地合并成一堆.规定每次只能选相邻的2堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分. 试设计出1个算法,计算出将N堆石子合并成1 ...