zoukankan      html  css  js  c++  java
  • 题解【CF277E Binary Tree on Plane】

    Description

    给你平面上 (n) 个点 ((2 leq n leq 400)),要求用这些点组成一个二叉树(每个节点的儿子节点不超过两个),定义每条边的权值为两个点之间的欧几里得距离。求一个权值和最小的二叉树,并输出这个权值。

    其中,点 (i) 可以成为点 (j) 的的父亲的条件是:点 (i)(y) 坐标比 (j)(y) 坐标大。

    如果不存在满足条件的二叉树,输出 (-1)

    Solution

    ((a,b)) 表示一条容量为 (a) ,费用为 (b) 的边
    把每个点 (u) 拆成两个点入点 (u_1) 和出点 (u_2)
    从源点向 (u_1) 连一条 ((2,0)),意义为限制了 (u) 只能有两个儿子
    (u_2) 向汇点连一条 ((1,0)) ,意义是限制了 (u) 最多只有一个父亲
    (u_y > v_y) 则在 (u_1)(v_2) 之间连一条 ((1,Len)),其中 Len 是两点之间的距离 (sqrt {(u_x - v_x)^2 + (u_y-v_y)^2})
    然后跑最小费用最大流完事。

    Code

    #include <bits/stdc++.h>
    #define db double
    using namespace std;
    const int N = 450; 
    const int INF = 1000000000;
    int n, k, S, T, vis[N], cnt, f[N * 2], pre[N * 2];
    db dis[N * 2];  
    struct edge {
      int v, f; db w; edge *next, *rev; 
    }pool[N * N], *head[N * 2], *r[N * 2];
    struct node {
      int sid, tid;
      db x, y; 
    }a[N]; 
    inline db Len(db x1, db y1, db x2, db y2) {
      return sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)); 
    }
    inline void addedge(int u, int v, int f, db w) {
      edge *p = &pool[++cnt], *q = &pool[++cnt];
      p->v = v, p->f = f, p->w = w, p->next = head[u], head[u] = p;  p->rev = q;  
      q->v = u, q->f = 0, q->w = -w, q->next = head[v], head[v] = q; q->rev = p; 
    }
    inline bool spfa() {
      for(int i = S; i <= T; i++) pre[i] = -1, dis[i] = INF, r[i] = NULL, vis[i] = 0; 
      queue <int> Q; Q.push(S), dis[S] = 0, vis[S] = 1; f[S] = INF; 
      while(!Q.empty()) {
        int u = Q.front(), v; Q.pop(); vis[u] = 0;
        for(edge *p = head[u]; p; p = p->next) {
          if(p->f && dis[v = p->v] > dis[u] + p->w) {
            dis[v] = dis[u] + p->w; 
            pre[v] = u, r[v] = p; 
            f[v] = min(f[u], p->f); 
            if(!vis[v]) vis[v] = 1, Q.push(v); 
          }
        }
      } return pre[T] != -1; 
    } int MF; db MC; 
    inline void MCMF() {
      while(spfa()) {
        for(int i = T; i != S; i = pre[i])
          r[i]->f -= f[T], r[i]->rev->f += f[T];
        MF += f[T], MC += 1.0 * dis[T] * f[T]; 
      } 
    }
    int main() {
      scanf("%d", &n); S = 0, T = 2 * n + 1; 
      for(int i = 1; i <= n; i++) {
        scanf("%lf %lf", &a[i].x, &a[i].y);
        a[i].sid = i * 2 - 1, a[i].tid = i * 2; 
        addedge(S, a[i].sid, 2, 0); 
        addedge(a[i].tid, T, 1, 0); 
      }
      for(int i = 1; i <= n; i++)
        for(int j = 1; j <= n; j++)
          if(i != j && a[i].y > a[j].y) 
            addedge(a[i].sid, a[j].tid, 1, Len(a[i].x, a[i].y, a[j].x, a[j].y)); 
      MCMF(); 
      if(MF == n - 1) printf("%lf
    ", MC); 
      else printf("-1
    ");
      return 0; 
    }
    
  • 相关阅读:
    nodejs第二天之Buffer类
    2019-2020-1 20175334 20175322 20175315 实验四 《外设驱动程序设计》实验报告
    2019-2020-1 20175315 20175322 20175334 实验三 实时系统
    2019-2020-2-20175315 20175322 20175334-实验二固件程序设计
    2019-2020-1 实验一 开发环境的熟悉
    2018-2019-20175315 实验五《网络编程与安全》实验报告
    实验四《Android程序设计》
    20175315Mycp
    20175315 实验二《Java面向对象程序设计》实验报告
    《Java程序设计》第七周学习总结
  • 原文地址:https://www.cnblogs.com/acfunction/p/10105432.html
Copyright © 2011-2022 走看看