Codeforces Round #170 (Div. 1) E. Binary Tree on Plane(費用流)

A root tree is a directed acyclic graph that contains one node (root), from which there is exactly one path to any other node.

A root tree is binary if each node has at most two outgoing arcs.

When a binary tree is painted on the plane, all arcs should be directed from top to bottom. That is, each arc going from u to v must meet the condition yu > yv.

You've been given the coordinates of all tree nodes. Your task is to connect these nodes by arcs so as to get the binary root tree and make the total length of the arcs minimum. All arcs of the built tree must be directed from top to bottom.

Input

The first line contains a single integer n (2 ≤ n ≤ 400) — the number of nodes in the tree. Then follow n lines, two integers per line: xi, yi(|xi|, |yi| ≤ 103) — coordinates of the nodes. It is guaranteed that all points are distinct.

Output

If it is impossible to build a binary root tree on the given points, print "-1". Otherwise, print a single real number — the total length of the arcs in the minimum binary tree. The answer will be considered correct if the absolute or relative error doesn't exceed 10 - 6.

Examples
input
3
0 0
1 0
2 1
output
3.650281539872885
input
4
0 0
1 0
2 1
2 0
output
-1

題意:給定平面上n個不同的點,縱座標大的點可以向下連邊且花費爲邊長,問把這n個點連成一顆二叉樹的最小花費是多少.

分析: 有連入有連出,考慮拆點,每個點拆成一個出點一個入點,源s向每個出點連一條容量爲2花費爲0的邊,除根以外的所有點向匯點t連一條容量爲1花費爲0的邊,然後在所有出點和入點間連上原圖可以連的容量爲1花費爲邊長的邊,最後跑一邊費用流就可以了,最大流不爲n-1時無解.

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 10000;
const int MAXM = 500000;
const int INF = 0x3f3f3f3f;
struct Edge
{
    int to,next,cap,flow;
    double cost;
} edge[MAXM];
int head[MAXN],tol;
int pre[MAXN];
double ans,dis[MAXN];
bool vis[MAXN];
int n,N;//節點總個數,節點編號從0~N-1
struct thing
{
    int x,y;
    friend bool operator < (thing a,thing b)
    {
        return a.y > b.y;
    }
}point[MAXN];
void init(int n)
{
    N = n;
    tol = 0;
    memset(head,-1,sizeof (head));
}
void addedge (int u,int v,int cap,double cost)
{
    edge[tol].to = v;
    edge[tol].cap = cap;
    edge[tol].cost = cost;
    edge[tol].flow = 0;
    edge[tol].next = head[u];
    head[u] = tol++;
    edge[tol].to = u;
    edge[tol].cap = 0;
    edge[tol].cost = -cost;
    edge[tol].flow = 0;
    edge[tol].next = head[v];
    head[v] = tol++;
}
bool spfa(int s,int t)
{
    queue<int>q;
    for(int i = 0; i < N; i++)
    {
        dis[i] = INF*1.0;
        vis[i] = false;
        pre[i] = -1;
    }
    dis[s] = 0;
    vis[s] = true;
    q.push(s);
    while(!q.empty())
    {
        int u = q.front();
        q.pop();
        vis[u] = false;
        for(int i = head[u]; i !=  -1; i = edge[i]. next)
        {
            int v = edge[i]. to;
            if(edge[i].cap > edge[i].flow &&
                    dis[v] > dis[u] + edge[i]. cost )
            {
                dis[v] = dis[u] + edge[i]. cost;
                pre[v] = i;
                if(!vis[v])
                {
                    vis[v] = true;
                    q.push(v);
                }
            }
        }
    }
    if(pre[t] == -1)return false;
    else return true;
}
//返回的是最大流,cost存的是最小費用
int minCostMaxflow(int s,int t,double &cost)
{
    int flow = 0;
    cost = 0;
    while(spfa(s,t))
    {
        int Min = INF;
        for(int i = pre[t]; i != -1; i = pre[edge[i^1].to])
        {
            if(Min > edge[i].cap - edge[i]. flow)
                Min = edge[i].cap - edge[i].flow;
        }
        for(int i = pre[t]; i != -1; i = pre[edge[i^1].to])
        {
            edge[i].flow += Min;
            edge[i^1].flow -= Min;
            cost += edge[i]. cost * Min;
        }
        flow += Min;
    }
    return flow;
}
double Dis(int x,int y)
{
    int a1 = point[x].x,b1 = point[x].y;
    int a2 = point[y].x,b2 = point[y].y;
    return sqrt(1.0*(a1-a2)*(a1-a2)+1.0*(b1-b2)*(b1-b2));
}
int main()
{
    cin.sync_with_stdio(false);
    cin>>n;
    for(int i = 1;i <= n;i++) cin>>point[i].x>>point[i].y;
    sort(point+1,point+1+n);
    if(point[1].y == point[2].y)
    {
        cout<<-1<<endl;
        return 0;
    }
    init(2*n+2);
    for(int i = 1;i <= n;i++) addedge(0,i,2,0);
    for(int i = 1;i <= n;i++)
     for(int j = i+1;j <= n;j++)
      if(point[i].y > point[j].y) addedge(i,n+j,1,Dis(i,j));
    for(int i = 2;i <= n;i++) addedge(n+i,2*n+1,1,0);
    int flow = minCostMaxflow(0,2*n+1,ans);
    if(flow != n-1)
    {
        cout<<-1<<endl;
        return 0;
    }
    printf("%.7f\n",ans);
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章