码迷,mamicode.com
首页 > 其他好文 > 详细

最小乘积生成树 bzoj 2395 Timeismoney

时间:2018-03-28 20:31:45      阅读:189      评论:0      收藏:0      [点我收藏+]

标签:==   AC   find   down   imei   www.   using   const   log   

http://www.lydsy.com/JudgeOnline/problem.php?id=2395

考虑在二维坐标系上
一种生成树方案\((cost, time)\)对应一个点
答案一定是在下凸包上的一段
我们考虑如何找到这个下凸包
首先找到两个初始点\(a, b\)
分别对应以\(cost\), \(time\)为最优
然后我们可以在\(a~b\)之间进行二分
找到离\(ab\)最远的点\(c\)
最小化\(\vec{ab} \times \vec{ac}\)也就是面积
然后对于每一条边 重新赋值
值为对答案的贡献 然后就枚举了所有下凸包的点
复杂度是\(O(S n \log n)\)
\(S\)是点对数 知乎上说是\(m^2\)级别的

#include<bits/stdc++.h>
#define int long long
#define fo(i, n) for(int i = 1; i <= (n); i ++)
#define out(x) cout << #x << " = " << x << "\n"
#define type(x) __typeof((x).begin())
#define foreach(it, x) for(type(x) it = (x).begin(); it != (x).end(); ++ i)
using namespace std;
// by piano
template<typename tp> inline void read(tp &x) {
  x = 0;char c = getchar(); bool f = 0;
  for(; c < '0' || c > '9'; f |= (c == '-'), c = getchar());
  for(; c >= '0' && c <= '9'; x = (x << 3) + (x << 1) + c - '0', c = getchar());
  if(f) x = -x;
}
template<typename tp> inline void arr(tp *a, int n) {
  for(int i = 1; i <= n; i ++)
    cout << a[i] << " ";
  puts("");
}
const int N = 233;
const int M = 11233;
struct E {
  int u, v, x, y, w;
  inline void in(void) {
    read(u); read(v); read(x); read(y);
    ++ u; ++ v;
  }
}e[M];

struct Node {
  int x, y;
  Node(int _x = 0, int _y = 0) {
    x = _x; y = _y;
  }
  inline void ovo(void) {
    cout << x << " " << y << "\n";
  }
}ans, minx, miny;
int n, m, pre[N];

inline Node operator - (Node a, Node b) {
  return Node(a.x - b.x, a.y - b.y);
}

inline int crs(Node a, Node b) {
  return a.x * b.y - a.y * b.x;
}

inline int find(int u) {
  return pre[u] == u ? u : pre[u] = find(pre[u]);
}

inline bool cmp_w(E a, E b) {
  return a.w < b.w;
}

inline Node doit(void) {
  for(int i = 1; i <= n; i ++)
    pre[i] = i;
  sort(e + 1, e + m + 1, cmp_w);
  Node now;
  for(int i = 1; i <= m; i ++) {
    int fx = find(e[i].u);
    int fy = find(e[i].v);
    if(fx != fy) {
      pre[fx] = fy;
      now.x += e[i].x;
      now.y += e[i].y;
    }
  }
  if(!ans.x || (ans.x * ans.y > now.x * now.y))
    ans = now;
  return now;
}

inline void work(Node a, Node b) {
  for(int i = 1; i <= m; i ++)
    e[i].w = e[i].y * (b.x - a.x) - e[i].x * (b.y - a.y);
  Node c = doit();
  if(crs(c - a, b - a) <= 0)
    return ;
  work(a, c); work(c, b);
}

main(void) {
  read(n); read(m);
  for(int i = 1; i <= m; i ++)
    e[i].in();
  for(int i = 1; i <= m; i ++)
    e[i].w = e[i].x;
  minx = doit();
  for(int i = 1; i <= m; i ++)
    e[i].w = e[i].y;
  miny = doit();
  work(minx, miny);
  cout << ans.x << " " << ans.y << "\n";
}

最小乘积生成树 bzoj 2395 Timeismoney

标签:==   AC   find   down   imei   www.   using   const   log   

原文地址:https://www.cnblogs.com/foreverpiano/p/8665534.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!