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

设每个点有x,y两个权值,求一棵生成树,使得sigma(x[i])*sigma(y[i])最小。
设每棵生成树为坐标系上的一个点,sigma(x[i])为横坐标,sigma(y[i])为纵坐标。则问题转化为求一个点,使得xy=k最小。即,使过这个点的反比例函数y=k/x最接近坐标轴。
Step1:求得分别距x轴和y轴最近的生成树(点):A、B(分别按x权值和y权值做最小生成树即可)。
Step2:寻找一个在AB的靠近原点一侧的且离AB最远的生成树C,试图更新答案。
【怎么找????
——由于C离AB最远,所以S△ABC面积最大。
向量AB=(B.x - A.x , B.y - A.y)
向量AC= (C.x - A.x , C.y - A.y)
向量AB、AC的叉积(的二分之一)为S△ABC的面积(只不过叉积是有向的,是负的,所以最小化这个值,即为最大化面积)。
最小化:(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 - A.y*(B.x-A.x)+A.x*(B.y-A.y)/*粗体为常数,不要管*/
所以将每个点的权值修改为 y[i]*(B.x-A.x)+(A.y-B.y)*x[i] 做最小生成树,找到的即是C。】
Step3:递归地分别往AC、BC靠近原点的一侧找。递归边界:该侧没有点了(即叉积大于等于零)。
BZOJ2395 裸题
Code:
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int res;
char c;
inline int Get()
{
res=;c='*';
while(c<''||c>'')c=getchar();
while(c>=''&&c<=''){res=res*+(c-'');c=getchar();}
return res;
}
struct Edge{int u,v,c,t,w;void read(){u=Get();v=Get();c=Get();t=Get();}};
struct Point{int x,y;Point(const int &A,const int &B){x=A;y=B;}Point(){}};
typedef Point Vector;
typedef long long LL;
Vector operator - (const Point &a,const Point &b){return Vector(a.x-b.x,a.y-b.y);}
int Cross(Vector A,Vector B){return A.x*B.y-A.y*B.x;}
bool operator < (const Edge &a,const Edge &b){return a.w<b.w;}
Edge edges[];
int n,m,rank[],fa[];
Point ans=Point(,),minc,mint;
inline void init()
{
memset(rank,,sizeof(rank));
for(int i=;i<n;i++)
fa[i]=i;
}
int findroot(int x)
{
if(fa[x]==x)
return x;
int t=findroot(fa[x]);
fa[x]=t;
return t;
}
inline void Union(int U,int V)
{
if(rank[U]<rank[V])
fa[U]=V;
else
{
fa[V]=U;
if(rank[U]==rank[V])
rank[U]++;
}
}
inline Point Kruscal()
{
int tot=;
Point now=Point(,);
init();
for(int i=;i<=m;i++)
{
int U=findroot(edges[i].u),V=findroot(edges[i].v);
if(U!=V)
{
Union(U,V);
tot++;
now.x+=edges[i].c;
now.y+=edges[i].t;
if(tot==n-)
break;
}
}
LL Ans=(LL)ans.x*ans.y,Now=(LL)now.x*now.y;
if( Ans>Now || (Ans==Now&&now.x<ans.x) )
ans=now;
return now;
}
void Work(Point A,Point B)
{
for(int i=;i<=m;i++)
edges[i].w=edges[i].t*(B.x-A.x)+edges[i].c*(A.y-B.y);
sort(edges+,edges+m+);
Point C=Kruscal();
if(Cross(B-A,C-A)>=)
return;
Work(A,C);
Work(C,B);
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=;i<=m;i++)
edges[i].read();
for(int i=;i<=m;i++)
edges[i].w=edges[i].c;
sort(edges+,edges+m+);
minc=Kruscal();
for(int i=;i<=m;i++)
edges[i].w=edges[i].t;
sort(edges+,edges+m+);
mint=Kruscal();
Work(minc,mint);
printf("%d %d\n",ans.x,ans.y);
return ;
}
【最小乘积生成树】bzoj2395[Balkan 2011]Timeismoney的更多相关文章
- bzoj2395[Balkan 2011]Timeismoney最小乘积生成树
所谓最小乘积生成树,即对于一个无向连通图的每一条边均有两个权值xi,yi,在图中找一颗生成树,使得Σxi*Σyi取最小值. 直接处理问题较为棘手,但每条边的权值可以描述为一个二元组(xi,yi),这也 ...
- bzoj2395: [Balkan 2011]Timeismoney
Description 有n个城市(编号从0..n-1),m条公路(双向的),从中选择n-1条边,使得任意的两个城市能够连通,一条边需要的c的费用和t的时间,定义一个方案的权值v=n-1条边 ...
- Bzoj2395: [Balkan 2011]Timeismoney(最小乘积生成树)
问题描述 每条边两个权值 \(x,y\),求一棵 \((\sum x) \times (\sum y)\) 最小的生成树 Sol 把每一棵生成树的权值 \(\sum x\) 和 \(\sum y\) ...
- BZOJ2395 [Balkan 2011]Timeismoney 【最小乘积生成树】
题目链接 BZOJ2395 题意:无向图中每条边有两种权值,定义一个生成树的权值为两种权值各自的和的积 求权值最小的生成树 题解 如果我们将一个生成树的权值看做坐标,那么每一个生成树就对应一个二维平面 ...
- bzoj2395 [Balkan 2011]Timeismoney(最小乘积生成树+计算几何)
题意 每条边有两个权值\(c,t\),请求出一颗生成树,使得\(\sum c\times \sum t\)最小 题解 为什么生成树会和计算几何扯上关系-- 对于每棵树,设\(x=c,y=t\),我们可 ...
- 【BZOJ2395】【Balkan 2011】Timeismoney 最小乘积生成树
链接: #include <stdio.h> int main() { puts("转载请注明出处[辗转山河弋流歌 by 空灰冰魂]谢谢"); puts("网 ...
- 【BZOJ2395】[Balkan 2011]Timeismoney
[BZOJ2395][Balkan 2011]Timeismoney 题面 \(darkbzoj\) 题解 如果我们只有一个条件要满足的话直接最小生成树就可以了,但是现在我们有两维啊... 我们将每个 ...
- HDU5697 刷题计划 dp+最小乘积生成树
分析:就是不断递归寻找靠近边界的最优解 学习博客(必须先看这个): 1:http://www.cnblogs.com/autsky-jadek/p/3959446.html 2:http://blog ...
- 【BZOJ】2395: [Balkan 2011]Timeismoney
题解 最小乘积生成树! 我们把,x的总和和y的总和作为x坐标和y左边,画在坐标系上 我们选择两个初始点,一个是最靠近y轴的A,也就是x总和最小,一个是最靠近x轴的B,也就是y总和最小 连接两条直线,在 ...
随机推荐
- setTimeOut和闭包
掘金上看到一个setTimeout与循环闭包的思考题.拿过来看了下,一方面了解settimeout的运行机制,还有就是js闭包的特性.关于闭包,有如下解释: 在这里写一点我对闭包的理解.理解闭包的关键 ...
- Coursera在线学习---第十节.大规模机器学习(Large Scale Machine Learning)
一.如何学习大规模数据集? 在训练样本集很大的情况下,我们可以先取一小部分样本学习模型,比如m=1000,然后画出对应的学习曲线.如果根据学习曲线发现模型属于高偏差,则应在现有样本上继续调整模型,具体 ...
- [一] sqlinject bypass
http://103.238.227.13:10087/?id=1 由源码来看是没有办法注入的,几乎都是过滤了的.但是经过测试加<>符号会被直接替换为空. 那么就可以借助此进行bypass ...
- DTW 算法(转)
DTW为(Dynamic Time Warping,动态时间归准)的简称.应用很广,主要是在模板匹配中,比如说用在孤立词语音识别,计算机视觉中的行为识别,信息检索等中.可能大家学过这些类似的课程都看到 ...
- java===java基础学习(14)---封装
package dog; public class Demo4 { public static void main(String []args) { Worker w1= new Worker(&qu ...
- 64_a1
AGReader-1.2-16.fc26.x86_64.rpm 13-Feb-2017 23:31 50654 ATpy-0.9.7-11.fc26.noarch.rpm 13-Feb-2017 22 ...
- python 命名规范最近遇到的问题
1.remove redundant parentheses 出去多余的括号,写C#习惯了先加个括号,python的if不用加括号. 改为:if chrome_args().get("hea ...
- 辨别苹果数据线真伪 苹果计算器 Dashboard 知识
辨别苹果数据线真伪 苹果计算器 Dashboard 知识 苹果数据线真伪的最简单的辨别: 线质柔软 用数据线连接适配器(苹果自带的适配器)充电 连接手机 如果该手机数据线是假的, 在手机上会提示”该 ...
- 怎么制作CHM格式电子书
CHM格式的帮助文件相信大家都不陌生,CHM文件形式多样,使用方便,深受大家喜爱. 今天给大家介绍一种把文本文件转换为CHM格式电子书的方法. 前期准备过程 1 下载QuickCHM v2.6文件 去 ...
- Java学习笔记(八)——java多线程
[前面的话] 实际项目在用spring框架结合dubbo框架做一个系统,虽然也负责了一块内容,但是自己的能力还是不足,所以还需要好好学习一下基础知识,然后做一些笔记.希望做完了这个项目可以写一些dub ...