1. 程式人生 > >題解【CF277E Binary Tree on Plane】

題解【CF277E Binary Tree on Plane】

nod += esp namespace code return () 如果 \n

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\n", MC); 
  else printf("-1\n");
  return 0; 
}

題解【CF277E Binary Tree on Plane】