题解

最小乘积生成树!

我们把,x的总和和y的总和作为x坐标和y左边,画在坐标系上

我们选择两个初始点,一个是最靠近y轴的A,也就是x总和最小,一个是最靠近x轴的B,也就是y总和最小

连接两条直线,在这条直线上面的点都不用考虑了

我们选一个离直线最远的点C,且在直线下方,我们用叉积考虑这个东西,也就是……面积最大!我们如果用最小生成树的话,只要让面积是负的就好了

推一下式子,发现是\((A.y - B.y) * C.x + (B.x - A.x) * C.y\)我们发现就是把边设置成

\((A.y - B.y) * E[i].c + (B.x - A.x) * E[i].t\)做一遍最小生成树

找到C点后递归处理A,C和C,B即可

边界是两点连线下方没有点也就是叉积大于等于0

代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <ctime>
#include <vector>
#include <set>
//#define ivorysi
#define eps 1e-8
#define mo 974711
#define pb push_back
#define mp make_pair
#define pii pair<int,int>
#define fi first
#define se second
#define MAXN 10005
#define space putchar(' ')
#define enter putchar('\n')
using namespace std;
typedef long long int64;
typedef unsigned int u32;
typedef unsigned long long u64;
typedef double db;
const int64 MOD = 1000000007;
template<class T>
void read(T &res) {
res = 0;char c = getchar();T f = 1;
while(c < '0' || c > '9') {
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9') {
res = res * 10 + c - '0';
c = getchar();
}
res *= f;
}
template<class T>
void out(T x) {
if(x < 0) putchar('-');
if(x >= 10) {
out(x / 10);
}
putchar('0' + x % 10);
}
int N,M;
struct Point {
int64 x,y;
int64 v;
Point(){};
Point(int64 _x,int64 _y) {
x = _x;y = _y;v = x * y;
}
friend bool operator < (const Point &a,const Point &b) {
return a.v < b.v || (a.v == b.v && a.x < b.x);
}
}ans;
struct Edge {
int u,v;
int64 c,t,w;
Edge(){}
Edge(int _u,int _v,int64 _c,int64 _t) {
u = _u;v = _v;c = _c;t = _t;
}
friend bool operator < (const Edge &a,const Edge &b) {
return a.w < b.w || (a.w == b.w && a.c < b.c);
}
}E[MAXN];
int fa[205];
int getfa(int u) {
return fa[u] == u ? u : fa[u] = getfa(fa[u]);
}
Point kruskal() {
sort(E + 1,E + M + 1);
Point res = Point(0,0);
for(int i = 1 ; i <= N ; ++i) fa[i] = i;
for(int i = 1 ; i <= M ; ++i) {
if(getfa(E[i].u) != getfa(E[i].v)) {
fa[getfa(E[i].u)] = getfa(E[i].v);
res.x += E[i].c;res.y += E[i].t;
}
}
res.v = res.x * res.y;
if(res < ans) ans = res;
return res;
}
void Work(Point A,Point B) {
for(int i = 1 ; i <= M ; ++i) {
E[i].w = (A.y - B.y) * E[i].c + (B.x - A.x) * E[i].t;
}
Point r = kruskal();
if((A.x - r.x) * (B.y - r.y) - (A.y - r.y) * (B.x - r.x) >= 0) return;
Work(A,r);
Work(r,B);
}
void Solve() {
read(N);read(M);
int u,v;
int64 c,t;
for(int i = 1 ; i <= M ; ++i) {
read(u);read(v);read(c);read(t);
++u;++v;
E[i] = Edge(u,v,c,t);
}
ans.v = 1e18;
for(int i = 1 ; i <= M ; ++i) {
E[i].w = E[i].c;
}
Point A = kruskal();
for(int i = 1 ; i <= M ; ++i) {
E[i].w = E[i].t;
}
Point B = kruskal();
Work(A,B);
printf("%lld %lld\n",ans.x,ans.y);
}
int main() {
#ifdef ivorysi
freopen("f1.in","r",stdin);
#endif
Solve();
return 0;
}

【BZOJ】2395: [Balkan 2011]Timeismoney的更多相关文章

  1. BZOJ 2395 [Balkan 2011]Timeismoney(最小乘积生成树)

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=2395 [题目大意] 给出一张无向图,每条边上有a,b两个值,求生成树, 使得suma* ...

  2. bzoj 2395: [Balkan 2011]Timeismoney【计算几何+最小生成树】

    妙啊,是一个逼近(?)的做法 把两个值最为平面上的点坐标,然后答案也是一个点. 首先求出可能是答案的点xy分别是按照c和t排序做最小生成树的答案,然后考虑比这两个点的答案小的答案,一定在xy连线靠近原 ...

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

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

  4. @bzoj - 2395@ [Balkan 2011]Timeismoney

    目录 @description@ @solution@ @accepted code@ @details@ @description@ 有n个城市(编号从0..n-1),m条公路(双向的),从中选择n ...

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

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

  6. 【BZOJ2395】[Balkan 2011]Timeismoney

    [BZOJ2395][Balkan 2011]Timeismoney 题面 \(darkbzoj\) 题解 如果我们只有一个条件要满足的话直接最小生成树就可以了,但是现在我们有两维啊... 我们将每个 ...

  7. 【BZOJ】3052: [wc2013]糖果公园

    http://www.lydsy.com/JudgeOnline/problem.php?id=3052 题意:n个带颜色的点(m种),q次询问,每次询问x到y的路径上sum{w[次数]*v[颜色]} ...

  8. 【BZOJ】3319: 黑白树

    http://www.lydsy.com/JudgeOnline/problem.php?id=3319 题意:给一棵n节点的树(n<=1e6),m个操作(m<=1e6),每次操作有两种: ...

  9. 【BZOJ】3319: 黑白树(并查集+特殊的技巧/-树链剖分+线段树)

    http://www.lydsy.com/JudgeOnline/problem.php?id=3319 以为是模板题就复习了下hld............................. 然后n ...

随机推荐

  1. Date时间格式比较大小

    方法一: 两个Date类型的变量可以通过compareTo方法来比较.此方法的描述是这样的:如果参数 Date 等于此 Date,则返回值 0:如果此 Date 在 Date 参数之前,则返回小于 0 ...

  2. enumerate 遍历numpy数组

    enumerate 遍历numpy数组 觉得有用的话,欢迎一起讨论相互学习~Follow Me 遍历一维数组 i,j 分别表示数组的 索引 和 存储的值 import numpy as np a=np ...

  3. 科学计算三维可视化---TraitsUI(Group对象组织界面)

    使用Group对象组织界面 将一组相关的Item对象组织在一起 from traitsui.api import Group from traits.api import HasTraits,Int, ...

  4. Git之简介及安装

    简介 Git是一个分布式版本控制系统,GitHub相当于一个远程仓库,注册账号可免费获得Git远程仓库. GitHub使用参考:https://guides.github.com/activities ...

  5. Web应用开发中的几个问题

    Introduction 由于Ajax技术在Gmail中的成功应用和高性能的V8引擎的推出使得编写Web应用变得流行 起来,使用前端技术也可以编写具有复杂交互的应用.相对于native应用,Web应用 ...

  6. linux查询进程 kill进程

    查询进程 #ps aux #查看全部进程 #ps aux|grep firewall #查询与firewall相关的进程 kill进程一 kill进程pid为711进程: #pkill -9 711 ...

  7. laravel new xxx 安装laravel 慢的问题

    问题:使用官方文档上安装 laravel laravel new xxx 安装速度奇慢无比,设置了composer 全局镜像也没有用 composer config -g repo.packagist ...

  8. Shell编程之运算符和环境变量配置文件

    一.shell运算符:    declare命令:         declare    -i 变量名     #声明变量        eg. movie[o]=dzp     #定义数组      ...

  9. git之合并分支(git merge)------(三)

    最近几天写小demo,总是自己拉取他人的代码,然后创建分支,在自己的分支上进行修改,然后提交到自己的分支,具体的这一步,我就不多讲了,因为在我的博客“工作中常用的Git操作”中有详细的介绍,今天主要讲 ...

  10. 《区块链100问》第73集:达世币Dash是什么?

    达世币诞生于2014年1月18日,匿名程度较比特币更高. 达世币有三种转账方式,一是像比特币一样的普通转账:二是即时交易.不需要矿工打包确认,就可以确认交易,几乎可以实现秒到:三是匿名交易.从区块链上 ...