題解【CF277E Binary Tree on Plane】
阿新 • • 發佈:2018-12-12
nod += esp namespace code return () 如果 \n
從源點向 \(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}\)
然後跑最小費用最大流完事。
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】