Bzoj2395: [Balkan 2011]Timeismoney(最小乘积生成树)
问题描述
每条边两个权值 \(x,y\),求一棵 \((\sum x) \times (\sum y)\) 最小的生成树
Sol
把每一棵生成树的权值 \(\sum x\) 和 \(\sum y\) 看成平面上的一个点 \((X,Y)\)
那么就是要求 \(X \times Y\) 最小
设 \(k=X \times Y\),则 \(Y = \frac{k}{X}\)
也就是要求这个反比例函数最靠近坐标轴
我们知道了 \(X\) 最小和 \(Y\) 最小的答案(两遍最小生成树)
设这两个点为 \(A,B\)
那么就是要在 \(AB\) 这条直线的左边找到一个距离最远的点 \(C\) 来更新当前答案
也就是向量 \(\vec {AB}\) 和 \(\vec {AC}\) 叉积最小(为负数,也就是面积)
即 \((Bx-Ax)\times (Cy-Ay)-(Cx-Ax) \times (By-Ay)\) 最小
化简就是 \((Bx-Ax)\times Cy-(By-Ay)\times Cx+...\) (省略号为常数)
那么每条边改一下权值为 \((Bx-Ax)\times y-(By-Ay)\times x\)
然后求一遍最小生成树求出 \(C\),递归处理 \(AC\) 和 \(CB\) 即可
p.s: 最小乘积匹配也可以这么做
# include <bits/stdc++.h>
# define IL inline
# define RG register
# define Fill(a, b) memset(a, b, sizeof(a))
# define File(a) freopen(a".in", "r", stdin), freopen(a".out", "w", stdout)
using namespace std;
typedef long long ll;
IL int Input(){
RG char c = getchar(); RG int x = 0, z = 1;
for(; c < '0' || c > '9'; c = getchar()) z = c == '-' ? -1 : 1;
for(; c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48);
return x * z;
}
const int maxn(205);
const int maxm(1e4 + 5);
const int inf(1e9);
int n, m, fa[maxn];
struct Point{
int x, y;
IL Point operator -(RG Point b) const{
return (Point){x - b.x, y - b.y};
}
IL Point operator +(RG Point b) const{
return (Point){x + b.x, y + b.y};
}
IL int operator *(RG Point b) const{
return x * b.y - y * b.x;
}
IL int operator <(RG Point b) const{
return x * y != b.x * b.y ? x * y < b.x * b.y : x < b.x;
}
} ans, mnc, mnt;
struct Edge{
int u, v, w, c, t;
IL int operator <(RG Edge b) const{
return w < b.w;
}
} edge[maxm];
IL int Find(RG int x){
return fa[x] == x ? x : fa[x] = Find(fa[x]);
}
IL Point Kruskal(){
for(RG int i = 1; i <= n; ++i) fa[i] = i;
RG Point ret = (Point){0, 0};
sort(edge + 1, edge + m + 1);
for(RG int i = 1, t = 0; t < n - 1 && i <= m; ++i){
RG int u = Find(edge[i].u), v = Find(edge[i].v);
if(u != v) fa[u] = v, ++t, ret = ret + (Point){edge[i].c, edge[i].t};
}
ans = min(ans, ret);
return ret;
}
IL void Solve(RG Point a, RG Point b){
RG int x = b.y - a.y, y = b.x - a.x;
for(RG int i = 1; i <= m; ++i) edge[i].w = y * edge[i].t - x * edge[i].c;
RG Point ret = Kruskal();
if((b - a) * (ret - a) >= 0) return;
Solve(a, ret), Solve(ret, b);
}
int main(RG int argc, RG char* argv[]){
File("2395");
ans = (Point){inf, 1}, n = Input(), m = Input();
for(RG int i = 1; i <= m; ++i) edge[i] = (Edge){Input() + 1, Input() + 1, 0, Input(), Input()};
for(RG int i = 1; i <= m; ++i) edge[i].w = edge[i].c;
mnc = Kruskal();
for(RG int i = 1; i <= m; ++i) edge[i].w = edge[i].t;
mnt = Kruskal();
Solve(mnc, mnt);
printf("%d %d\n", ans.x, ans.y);
return 0;
}
Bzoj2395: [Balkan 2011]Timeismoney(最小乘积生成树)的更多相关文章
- bzoj2395[Balkan 2011]Timeismoney最小乘积生成树
所谓最小乘积生成树,即对于一个无向连通图的每一条边均有两个权值xi,yi,在图中找一颗生成树,使得Σxi*Σyi取最小值. 直接处理问题较为棘手,但每条边的权值可以描述为一个二元组(xi,yi),这也 ...
- bzoj 2395 [Balkan 2011]Timeismoney——最小乘积生成树
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2395 如果把 \( \sum t \) 作为 x 坐标,\( \sum c \) 作为 y ...
- 【BZOJ2395】【Balkan 2011】Timeismoney 最小乘积生成树
链接: #include <stdio.h> int main() { puts("转载请注明出处[辗转山河弋流歌 by 空灰冰魂]谢谢"); puts("网 ...
- bzoj2395: [Balkan 2011]Timeismoney
Description 有n个城市(编号从0..n-1),m条公路(双向的),从中选择n-1条边,使得任意的两个城市能够连通,一条边需要的c的费用和t的时间,定义一个方案的权值v=n-1条边 ...
- BZOJ2395 [Balkan 2011]Timeismoney 【最小乘积生成树】
题目链接 BZOJ2395 题意:无向图中每条边有两种权值,定义一个生成树的权值为两种权值各自的和的积 求权值最小的生成树 题解 如果我们将一个生成树的权值看做坐标,那么每一个生成树就对应一个二维平面 ...
- bzoj2395 [Balkan 2011]Timeismoney(最小乘积生成树+计算几何)
题意 每条边有两个权值\(c,t\),请求出一颗生成树,使得\(\sum c\times \sum t\)最小 题解 为什么生成树会和计算几何扯上关系-- 对于每棵树,设\(x=c,y=t\),我们可 ...
- 【最小乘积生成树】bzoj2395[Balkan 2011]Timeismoney
设每个点有x,y两个权值,求一棵生成树,使得sigma(x[i])*sigma(y[i])最小. 设每棵生成树为坐标系上的一个点,sigma(x[i])为横坐标,sigma(y[i])为纵坐标.则问题 ...
- P5540-[BalkanOI2011]timeismoney|最小乘积生成树【最小生成树,凸壳】
正题 题目链接:https://www.luogu.com.cn/problem/P5540 题目大意 给出\(n\)个点\(m\)条边边权是一个二元组\((a_i,b_i)\),求出一棵生成树最小化 ...
- 洛谷 P5540 - [BalkanOI2011] timeismoney | 最小乘积生成树(最小生成树)
洛谷题面传送门 大概是一个比较 trivial 的小 trick?学过了就不要忘了哦( 莫名奇妙地想到了 yyq 的"hot tea 不常有,做过了就不能再错过了" 首先看到这种二 ...
随机推荐
- Asp.net的生命周期之应用程序生命周期
参考:http://msdn.microsoft.com/zh-cn/library/ms178473(v=vs.100).aspx 参考:http://www.cnblogs.com/JimmyZh ...
- 【转载】基于Redis实现分布式锁
背景在很多互联网产品应用中,有些场景需要加锁处理,比如:秒杀,全局递增ID,楼层生成等等.大部分的解决方案是基于DB实现的,Redis为单进程单线程模式,采用队列模式将并发访问变成串行访问,且多客户端 ...
- 42.oracle物化视图
写在前面 先大概列一下数据库表设计的常规流程.方案.要遵循的规则 根据业务切分设计表 逻辑分层(数据库分层) 数据库结构设计与拆分:水平拆分(mysql分片)oracle分区物化视图中间表设计方案 优 ...
- 架构师养成记--34.Redis持久化
---恢复内容开始--- redis是一个支持持久化的内存数据库,也就是搜redis需要经常将内存中的数据同步到硬盘来保证持久化.redis持久化有两种方式. snapshotting(快照)默认方式 ...
- day5:python学习之集合
0. 集合的作用及特点 集合具有去重和关系测试两大作用,它具有无序的特点. list1 = [1,2,3,4,5,7,6,8,6,4] list1 = set(list1) print(list1) ...
- mysql 与sqlser group by
mysql select * ,count(1) from simccbillm18 group by MonthNum; SqlSer select col1,col2 from table g ...
- python里有意思的文件查找glob模块
python标准库之glob介绍 glob 文件名模式匹配,不用遍历整个目录判断每个文件是不是符合. 1.通配符 星号(*)匹配零个或多个字符 import glob for name in glob ...
- BiliBili, ACFun… And More!【递归算法】
题源:http://acm.uestc.edu.cn/#/problem/show/3 题解: 题意:播放一段视频文件,有播放速度和缓冲速度两种,因为作者的癖好,播放前要缓冲几秒钟(这段时间不计算在总 ...
- 一个好用的ssh终端:MobaXterm
WSL由于没有图形界面,所有操作都是在命令行里执行,平时用来编译和跑CFD代码其实还是挺方便.不过有时候要查看WSL里的文件就比较麻烦,这时可以用SFTP这类工具,连接过去后直接操作文件.试过几个这类 ...
- 警告: Hessian/Burlap: 'com.github.pagehelper.Page' is an unknown class in WebappClassLoader
项目中使用mybatis的分页插件pagehelper出现下面的警告 出现上面的警告,并不影响程序的运行.但是毕竟看着比较闹心. 使用debug进行代码根据发现,执行的过程中使用到了pagehelpe ...