bzoj2395 [Balkan 2011]Timeismoney

题意:每条边有两个权值a,b,求图的最小二元和乘积生成树(即该树的sum_a*sum_b最小)。

标程:

 1 #include<bits/stdc++.h>
 2 #define P pair<ll,ll>
 3 #define fir first
 4 #define sec second
 5 using namespace std;
 6 typedef long long ll;
 7 int read()
 8 {
 9    int x=0,f=1;char ch=getchar();
10    while (ch<‘0‘||ch>‘9‘) {if (ch==‘-‘) f=-1;ch=getchar();}
11    while (ch>=‘0‘&&ch<=‘9‘) x=(x<<1)+(x<<3)+ch-‘0‘,ch=getchar();
12    return x*f;
13 }
14 const int N=10005;
15 int f[N],n,m;
16 ll ans,qa,qb;
17 struct node{ll u,v,a,b,w;}e[N];
18 int find(int x){return x==f[x]?x:f[x]=find(f[x]);}
19 bool cmp_a(const node &A,const node &B){return A.a<B.a;}
20 bool cmp_b(const node &A,const node &B){return A.b<B.b;}
21 bool cmp_w(const node &A,const node &B){return A.w<B.w;}
22 ll chaji(P A,P B,P C){return (B.fir-A.fir)*(C.sec-A.sec)-(B.sec-A.sec)*(C.fir-A.fir);}
23 P mst()
24 {
25     ll s1=0,s2=0;
26     for (int i=1;i<=n;i++) f[i]=i;
27     for (int i=1;i<=m;i++)
28       if (find(e[i].u)!=find(e[i].v))
29         f[find(e[i].u)]=find(e[i].v),s1+=e[i].a,s2+=e[i].b;
30     ll t=s1*s2;
31     if (t<ans) ans=t,qa=s1,qb=s2;
32       else if (t==ans&&s1<qa) qa=s1,qb=s2;
33     return P(s1,s2);
34 }
35 void solve(P A,P B)
36 {
37    for (int i=1;i<=m;i++)
38      e[i].w=(B.fir-A.fir)*e[i].b-(B.sec-A.sec)*e[i].a;
39    sort(e+1,e+m+1,cmp_w);P C=mst();
40     if (chaji(A,B,C)>=0) return;
41     solve(A,C);solve(C,B);
42 }
43 int main()
44 {
45     n=read();m=read();ans=1ll<<60;
46     for (int i=1;i<=m;i++) e[i].u=read()+1,e[i].v=read()+1,e[i].a=read(),e[i].b=read();
47     sort(e+1,e+m+1,cmp_a);P A=mst();
48     sort(e+1,e+m+1,cmp_b);P B=mst();
49     solve(A,B);
50     printf("%lld %lld\n",qa,qb);
51    return 0;
52 }

题解:数形结合+凸包

把每棵生成树按照(sum_a,sum_b)映射到坐标系上,基于乘积的反比例函数性质,动态维护下凸包。

具体地,先找到sum_a最小的点A和sum_b最小的点B,连边,在这条线的下方找到一个距离这条直线最远的点C。那么△ABC中的点一定不及三个端点的答案小。继续AC连边和CB连边找下方点,分治。并对端点统计。

难点在于最远点怎么求?转换成三角形面积最大,用叉积表示,其中一条边已知。向量AB叉乘向量AC=(B.x-A.x)*C.y-(B.y-A.y)*C.x-A.y*(B.x-A.x)+A.x*(B.y-A.y)(这是负的,使其最小)前两项和C有关,后两项都已知,重新对边赋权为(B.x-A.x)*e[i].b-(B.y-A.y)*e[i].a,跑mst,即为C点。

最坏复杂度O(nmlogm)。

如果是三元,那么就相当于在平面下找最远点,使得中间体积最大。分割的时候分成三个部分。

原文地址:https://www.cnblogs.com/Scx117/p/9179251.html

时间: 2024-08-03 09:12:28

bzoj2395 [Balkan 2011]Timeismoney的相关文章

【最小乘积生成树】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离

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

所谓最小乘积生成树,即对于一个无向连通图的每一条边均有两个权值xi,yi,在图中找一颗生成树,使得Σxi*Σyi取最小值. 直接处理问题较为棘手,但每条边的权值可以描述为一个二元组(xi,yi),这也就不难想到将生成树转化为平面内的点,x代表Σxi,y代表Σyi(注意这里的xi,yi指的是在生成树中的边的权值),那么问题就变成了在平面内找一个点使得x*y最小,那么显然这个点是在下凸壳上的. 因此可以首先找出两个一定在凸包上的点,例如A(minx,y),B(miny,x),在直线AB下方找一个在凸

【BZOJ 2395】 [Balkan 2011]Timeismoney

2395: [Balkan 2011]Timeismoney Time Limit: 10 Sec Memory Limit: 128 MB Submit: 304 Solved: 169 [Submit][Status][Discuss] Description 有n个城市(编号从0..n-1),m条公路(双向的),从中选择n-1条边,使得任意的两个城市能够连通,一条边需要的c的费用和t的时间,定义一个方案的权值v=n-1条边的费用和*n-1条边的时间和,你的任务是求一个方案使得v最小 Inp

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

链接: #include <stdio.h> int main() { puts("转载请注明出处[辗转山河弋流歌 by 空灰冰魂]谢谢"); puts("网址:blog.csdn.net/vmurder/article/details/46828379"); } 题解: 裸最小乘积生成树. 最小乘积生成树定义: 有一张n个点m条边的无向图,每条边有k个权值. 现在要取一个边集M使得其将所有点连通,并使 ∏ki=1(∑j∈Mjcost(j,vali))

BZOJ2440 [中山市选2011]完全平方数

Description 小 X 自幼就很喜欢数.但奇怪的是,他十分讨厌完全平方数.他觉得这些数看起来很令人难受.由此,他也讨厌所有是完全平方数的正整数倍的数.然而这丝毫不影响他对其他数的热爱. 这天是小X的生日,小 W 想送一个数给他作为生日礼物.当然他不能送一个小X讨厌的数.他列出了所有小X不讨厌的数,然后选取了第 K个数送给了小X.小X很开心地收下了. 然而现在小 W 却记不起送给小X的是哪个数了.你能帮他一下吗? Input 包含多组测试数据.文件第一行有一个整数 T,表示测试数据的组数.

开始使用CCA CRM 2011

你可能从微软的市场动态获知我们最近发布了最新版本的Microsoft Dynamics CRM 2011的客户关怀加速器(CCA R2).CCA在一个单一的用户界面提供呼叫中心功能相结合的,能够显示和操纵来自不同业务应用程序的数据.CCA提供了许多功能,包括: l 集成代理的桌面 l 脚本以消除重复的数据输入 l 计算机电话集成(CTI) l 代理活动报告 CCA的核心是一个允许开发人员构建自己的代理的桌面,并提供多会话管理等功能的框架.UI集成不同类型的应用程序(包括Web.Windows窗体

PowerShape 2011 R3 SP1 Update Only Win32 1CD

TraceParts v2.3-ISO 1CD VisCAM.RP.v5.2.8600 1CD  Beta-CAE ANSA.v13.1.2.Win64 1CD CEI.Ensight.Gold.v9.2.2b.Linux64.Debian 1CD CEI.Ensight.Gold.v9.2.2b.MacOSX 1CD InfinySlice.v1.0.8581 1CD Leica.LISCAD.v9.0.3 1CD  AFT Impulse v4.0 2011.04.21 1CD AgroKa

国家集训队2011 happiness

[试题来源] 2011中国国家集训队命题答辩 [问题描述] 高一一班的座位表是个n*m的矩阵,经过一个学期的相处,每个同学和前后左右相邻的同学互相成为了好朋友.这学期要分文理科了,每个同学对于选择文科与理科有着自己的喜悦值,而一对好朋友如果能同时选文科或者理科,那么他们又将收获一些喜悦值.作为计算机竞赛教练的scp大老板,想知道如何分配可以使得全班的喜悦值总和最大. [输入格式] 第一行两个正整数n,m.接下来是六个矩阵第一个矩阵为n行m列 此矩阵的第i行第j列的数字表示座位在第i行第j列的同学

贪心—— P1809 过河问题_NOI导刊2011提高(01)

洛谷——P1809 过河问题_NOI导刊2011提高(01) 题目描述 有一个大晴天,Oliver与同学们一共N人出游,他们走到一条河的东岸边,想要过河到西岸.而东岸边有一条小船. 船太小了,一次只能乘坐两人.每个人都有一个渡河时间T,船划到对岸的时间等于船上渡河时间较长的人所用时间. 现在已知N个人的渡河时间T,Oliver想要你告诉他,他们最少要花费多少时间,才能使所有人都过河. 注意,只有船在东岸(西岸)的人才能坐上船划到对岸. 输入输出格式 输入格式: 输入文件第一行为人数N,以下有N行