@description@

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

Input

第一行两个整数n,m,接下来每行四个整数a,b,c,t,表示有一条公路从城市a到城市b需要t时间和费用c

Output

仅一行两个整数sumc,sumt,(sumc表示使得v最小时的费用和,sumc表示最小的时间和) 如果存在多个解使得sumc*sumt相等,输出sumc最小的

Sample Input

5 7

0 1 161 79

0 2 161 15

0 3 13 153

1 4 142 183

2 4 236 80

3 4 40 241

2 1 65 92

Sample Output

279 501

HINT

【数据规模】

1<=N<=200, 1<=m<=10000, 0<=a,b<=n-1, 0<=t,c<=255。

有5%的数据m=n-1

有40%的数据有t=c

对于100%的数据如上所述

@solution@

非常经典的题.jpg。

假如将 (sumc, sumt) 看成一个坐标,那么一个可行生成树方案对应了坐标系中的一个点。

可以发现:只有下凸包上的点才可能成为答案。

如果不在下凸包上,那么可以作原点到该点的直线,它与凸包的交点显然更优。

同时,一条线段肯定取两个端点得到的乘积最小(写出表达式发现是二次函数)。

因为三点共线肯定不优,所以凸包上的斜率互不相同且递减。因此,凸包上的点最多只有 \(O(\sqrt{N*\max\{c, t\}})\) 个点。

我们只需要尝试找出凸包上的点并更新答案即可。

考虑两个必定在凸包内的点 A(minx, y) 与 B(x, miny)(不可能找到更大的凸包严格包含这两个点)。

如果忽视掉下凸包中斜率为正的部分(这部分肯定不优),这两个点就是凸包上的点横纵坐标的边界。

我们根据直线 AB,找该直线在凸包上对应的切线,就可以又找到一个新的凸包上的点。

其实就是距离 AB 最远的点 C。距离最远可以转成 ABC 的面积最大,然后可以写出叉积。

根据叉积式子再做一遍最大生成树(注意是最大)就可以找到 C 了。

然后分治 AC, CB 即可。

时间复杂度的一个上界为 \(O(\sqrt{N*\max\{c, t\}}*M\log M)\)。

@accepted code@

  1. #include <cstdio>
  2. #include <algorithm>
  3. using namespace std;
  4. const int MAXN = 200;
  5. const int MAXM = 10000;
  6. const int INF = int(1E9);
  7. typedef long long ll;
  8. int n, m;
  9. struct point{
  10. int c, t; ll k;
  11. point(int _c=0, int _t=0) : c(_c), t(_t), k(1LL*_c*_t) {}
  12. friend point operator + (point a, point b) {
  13. return point(a.c + b.c, a.t + b.t);
  14. }
  15. }ans(INF, INF);
  16. void update(point p) {
  17. if( p.k < ans.k || (p.k == ans.k && p.c < ans.c) )
  18. ans = p;
  19. }
  20. int a, b;
  21. struct edge{
  22. int u, v; point p;
  23. ll get() {return 1LL*a*p.c + 1LL*b*p.t;}
  24. friend bool operator < (edge a, edge b) {
  25. return a.get() < b.get();
  26. }
  27. }e[MAXM + 5];
  28. int fa[MAXN + 5];
  29. int find(int x) {
  30. return fa[x] = (fa[x] == x ? x : find(fa[x]));
  31. }
  32. point get() {
  33. for(int i=1;i<=n;i++) fa[i] = i;
  34. sort(e + 1, e + m + 1);
  35. point ret(0, 0);
  36. for(int i=1;i<=m;i++) {
  37. int fu = find(e[i].u), fv = find(e[i].v);
  38. if( fu != fv ) {
  39. ret = ret + e[i].p;
  40. fa[fu] = fv;
  41. }
  42. }
  43. return ret;
  44. }
  45. void solve(point A, point B) {
  46. a = (A.t - B.t), b = (B.c - A.c);
  47. point C = get();
  48. if( a*C.c + b*C.t + (B.t - A.t)*B.c + (A.c - B.c)*B.t >= 0 )
  49. return ;
  50. update(C), solve(A, C), solve(C, B);
  51. }
  52. int main() {
  53. scanf("%d%d", &n, &m);
  54. for(int i=1;i<=m;i++) {
  55. scanf("%d%d%d%d", &e[i].u, &e[i].v, &e[i].p.c, &e[i].p.t);
  56. e[i].u++, e[i].v++;
  57. }
  58. a = 1, b = 0; point A = get(); update(A);
  59. a = 0, b = 1; point B = get(); update(B);
  60. solve(A, B);
  61. printf("%d %d\n", ans.c, ans.t);
  62. }

@details@

其实这个模型之所以经典,是因为它的可迁移性很强。

比如给你整一个下一次最小乘积最短路,最小乘积最小割之类的。

另外,我们 01 分数规划 + 最小生成树,尽管平时用的是二分,其实也可以采用几何方法来做。

但是复杂度就很玄妙了。

@bzoj - 2395@ [Balkan 2011]Timeismoney的更多相关文章

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

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

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

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

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

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

  4. 【BZOJ】2395: [Balkan 2011]Timeismoney

    题解 最小乘积生成树! 我们把,x的总和和y的总和作为x坐标和y左边,画在坐标系上 我们选择两个初始点,一个是最靠近y轴的A,也就是x总和最小,一个是最靠近x轴的B,也就是y总和最小 连接两条直线,在 ...

  5. BZOJ 2395 [Balkan 2011]Time is money

    题面 题解 将\(\sum_i c_i\)和\(\sum_i t_i\)分别看做分别看做\(x\)和\(y\),投射到平面直角坐标系中,于是就是找\(xy\)最小的点 于是可以先找出\(x\)最小的点 ...

  6. 【BZOJ2395】[Balkan 2011]Timeismoney

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

  7. bzoj2395: [Balkan 2011]Timeismoney

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

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

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

  9. BZOJ2395:[Balkan 2011]Timeismoney——题解

    https://www.lydsy.com/JudgeOnline/problem.php?id=2395 有n个城市(编号从0..n-1),m条公路(双向的),从中选择n-1条边,使得任意的两个城市 ...

随机推荐

  1. UVA10905 Children's Game

    题意:给定n个正整数,把它们连接成一个最大的整数.比如,123,124,556,90有24种连接方法,最大的结果为9 056 124 123. 贪心.一开始就想用string水过.注意不能直接用str ...

  2. MySQL--修改Mac中的默认编码

    1.在终端中进入到etc目录下 2.打开etc目录下的my.cnf文件(如果这样修改不了的就要提高用户权限, 可以尝试使用sudo来打开文件) 3.将一下内容添加到my.cnf文件中 [client] ...

  3. Python 数据文件操作——写出数据

  4. yield函数的执行顺序

    例子: 上图中标明了  行号出现的顺序 从顺序中可以看到 1.开始先执行for循环,执行到93行yield_test(1)时,会调用函数yield_test(),所以打印了79行内容 2.到80行时, ...

  5. CSS基础强化

    1. 浮动引起元素变成行内块元素-display:inline-block <div style="width: 400px;height: 200px;"> < ...

  6. Django项目:CRM(客户关系管理系统)--09--04PerfectCRM实现King_admin注册功能01

  7. LUOGU P1053 篝火晚会 (Noip 2015 )

    题目描述 佳佳刚进高中,在军训的时候,由于佳佳吃苦耐劳,很快得到了教官的赏识,成为了"小教官".在军训结束的那天晚上,佳佳被命令组织同学们进行篝火晚会.一共有 nnn 个同学,编号 ...

  8. CentOS7使用iptables防火墙开放端口

    背景:在CentOS上面安装了mysql.svn.tomcat等软件,发现访问不了,用telnet命令查看端口,发现都不通: telnet IP 端口 CentOS7 默认使用firewalld防火墙 ...

  9. 百度DMLC分布式深度机器学习开源项目(简称“深盟”)上线了如xgboost(速度快效果好的Boosting模型)、CXXNET(极致的C++深度学习库)、Minerva(高效灵活的并行深度学习引擎)以及Parameter Server(一小时训练600T数据)等产品,在语音识别、OCR识别、人脸识别以及计算效率提升上发布了多个成熟产品。

    百度为何开源深度机器学习平台?   有一系列领先优势的百度却选择开源其深度机器学习平台,为何交底自己的核心技术?深思之下,却是在面对业界无奈时的远见之举.   5月20日,百度在github上开源了其 ...

  10. 动态生成能够局部刷新的验证码【AJAX技术】---看了不懂赔你钱

    在开发JavaWeb应用时,动态生成能够局部刷新的验证码是一项必须的功能,在这里我们将会详细的讲解如何实现这一功能. 一.涉及技术 该功能需要用到AJAX异步传输技术,这样能保证在点击"看不 ...