Binary Tree on Plane【费用流】

题目链接 CF 277 E


题意翻译

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

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

如果不存在满足条件的二叉树,输出 −1 。


  我们知道二叉树所满足的性质,每个结点的根只有一个(除了根结点外),并且每个结点的子结点最多有两个,所以我们可以根据这两个信息来搭建网络流的框架。

  把每个点拆成两个点,分别代表的是“作为根”“作为子结点”。然后就方便连接了,那些可以作为二叉树上的边,肯定是由“作为根”的结点连接向“作为子结点”的结点的,并且权值也好确定,就是两者的欧几里得距离。然后每个点的子结点最多有两个,每个点的作为根结点最多一次。这两个限制条件用上,我们的一张图也就构建出来了。

  • 用S连接向“作为子结点”的结点,流为2,费用为0。表示的是每个结点最多有两个子结点;
  • 用“作为根”的结点连接向T,表示每个点只能作为根一次,当然,这里需要排除1这号根结点;
  • “作为根”的结点向可行的“作为子结点”的结点连接相关费用的边,流为1,费用为二者的欧几里得距离。

  图就这样建完了。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <bitset>
#include <unordered_map>
#include <unordered_set>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 1e9 + 7.
#define eps 1e-8
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
#define MP(a, b) make_pair(a, b)
using namespace std;
typedef unsigned long long ull;
typedef unsigned int uit;
typedef long long ll;
const int maxN = 8e2 + 7, maxM = 2e5 + 7;
int N, head[maxN], cnt;
pair<double, double> a[405];
inline bool cmp(pair<double, double> e1, pair<double, double> e2) { return e1.second == e2.second ? e1.first < e2.first : e1.second > e2.second; }
inline double _Dis(pair<double, double> e1, pair<double, double> e2) { return sqrt((e1.first - e2.first) * (e1.first - e2.first) + (e1.second - e2.second) * (e1.second - e2.second)); }
struct Eddge
{
    int nex, u, v; int flow; double cost;
    Eddge(int a=-1, int _u=0, int _v=0, int b=0, double c=0.):nex(a), u(_u), v(_v), flow(b), cost(c) {}
}edge[maxM];
inline void addEddge(int u, int v, int f, double c)
{
    edge[cnt] = Eddge(head[u], u, v, f, c);
    head[u] = cnt++;
}
inline void _add(int u, int v, int f, double c) { addEddge(u, v, f, c); addEddge(v, u, 0, -c); }
struct MaxFlow_MinCost
{
    int pre[maxN], S, T, sum_of_Flow; int Flow[maxN]; double dist[maxN];
    queue<int> Q;
    bool inque[maxN];
    inline bool spfa()
    {
        for(int i=0; i<=T; i++) { pre[i] = -1; dist[i] = INF; inque[i] = false; }
        while(!Q.empty()) Q.pop();
        Q.push(S); dist[S] = 0.; inque[S] = true; Flow[S] = INF;
        while(!Q.empty())
        {
            int u = Q.front(); Q.pop(); inque[u] = false;
            int f; double w;
            for(int i=head[u], v; ~i; i=edge[i].nex)
            {
                v = edge[i].v; f = edge[i].flow; w = edge[i].cost;
                if(f && dist[v] > dist[u] + w + eps)
                {
                    dist[v] = dist[u] + w;
                    Flow[v] = min(Flow[u], f);
                    pre[v] = i;
                    if(!inque[v])
                    {
                        inque[v] = true;
                        Q.push(v);
                    }
                }
            }
        }
        return ~pre[T];
    }
    inline double EK()
    {
        double sum_Cost = 0;
        while(spfa())
        {
            int now = T, las = pre[now];
            while(now ^ S)
            {
                edge[las].flow -= Flow[T];
                edge[las ^ 1].flow += Flow[T];
                now = edge[las].u;
                las = pre[now];
            }
            sum_Cost += dist[T] * Flow[T];
            sum_of_Flow += Flow[T];
        }
        return sum_Cost;
    }
} MF;
inline void init()
{
    cnt = 0; MF.S = 2 * N + 1; MF.T = MF.S + 1; MF.sum_of_Flow = 0;
    for(int i=0; i<=MF.T; i++) head[i] = -1;
    for(int i=1; i<=N; i++) _add(MF.S, N + i, 2, 0);
    for(int i=2; i<=N; i++) _add(i, MF.T, 1, 0);
}
int main()
{
    scanf("%d", &N);
    init();
    for(int i=1; i<=N; i++) scanf("%lf%lf", &a[i].first, &a[i].second);
    sort(a + 1, a + N + 1, cmp);
    if(a[1].second == a[2].second) { printf("-1\n"); return 0; }
    for(int i=1; i<=N; i++)
    {
        for(int j=i+1; j<=N; j++)
        {
            if(a[i].second == a[j].second) continue;
            _add(N + i, j, 1, _Dis(a[i], a[j]));
        }
    }
    double ans = MF.EK();
    if(MF.sum_of_Flow == N - 1) printf("%lf\n", ans);
    else printf("-1\n");
    return 0;
}
发布了852 篇原创文章 · 获赞 1016 · 访问量 11万+

猜你喜欢

转载自blog.csdn.net/qq_41730082/article/details/104781082
今日推荐