[Codeforces 277E][Round #170 div.1 E]Binary Tree on Plane

題目大意:平面上給出K個點,每個點可以向縱座標比它小的點連邊,邊權爲歐幾里得距離,求一棵最小二叉生成樹。
每個點只有一條入邊,至多有兩條出邊,考慮使用最小費用最大流模型。
每個點拆成兩個點i,i’,對於原圖上的邊u,v,u向v’連一條容量爲1,費用爲dis的邊,源點向每個i連容量爲2費用爲0的邊,每個i’向匯點連一條容量爲1費用爲0的邊,最後檢查除了最上面那個點的出邊之外是否滿流即可。

#include<ctime>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<string>
#include<cassert>
#include<cmath>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<sstream>
#include<climits>
#define X first
#define Y second
#define DB double
#define lc now<<1
#define rc now<<1|1
#define MP make_pair
#define LL long long
#define pb push_back
#define sqr(_) ((_)*(_))
#define INF 0x3f3f3f3f
#define pii pair<int,int>
#define pdd pair<DB,DB>
#define ull unsigned LL
#define DEBUG(...) fprintf(stderr,__VA_ARGS__)
using namespace std;
template<typename T>void Read(T& x)
{
    x=0;int flag=0,sgn=1;char c;
    while(c=getchar())
    {
        if(c=='-')sgn=-1;
        else if(c>='0'&&c<='9')x*=10,x+=c-'0',flag=1;
        else if(flag)break;
    }
    x*=sgn;
}
const int MAXN=1000;
int n;
pdd pot[MAXN];
bool cmp(const pdd& x,const pdd& y)
{
    return x.Y==y.Y?x.X<y.X:x.Y<y.Y;
}
DB dis(const pdd& x,const pdd& y)
{
    return sqrt(sqr(x.X-y.X)+sqr(x.Y-y.Y));
}
struct Edge{
    int u,v,cap,flow;
    DB cost;
    Edge(int u=0,int v=0,int cap=0,int flow=0,DB cost=0):
        u(u),v(v),cap(cap),flow(flow),cost(cost){}
};
struct Mincost{
    vector<int> G[MAXN];
    vector<Edge> edges;
    int a[MAXN],p[MAXN],inq[MAXN],S,T;
    DB d[MAXN];
    void add(int u,int v,int c,DB co)
    {
        edges.pb(Edge(u,v,c,0,co));
        edges.pb(Edge(v,u,0,0,-co));
        int K=edges.size();
        G[u].pb(K-2);
        G[v].pb(K-1); 
    }
    bool SPFA(int& flow,DB& cost)
    {
        for(int i=0;i<MAXN;i++)d[i]=INF;
        memset(p,0,sizeof(p));
        memset(a,INF,sizeof(a)); 
        queue<int> q;
        q.push(S);
        inq[S]=1;
        d[S]=0;
        while(!q.empty())
        {
            int u=q.front();q.pop();
            inq[u]=0;
            for(int i=0;i<G[u].size();i++)
            {
                Edge& e=edges[G[u][i]];
                if(e.cap>e.flow&&d[e.v]>d[e.u]+e.cost)
                {
                    d[e.v]=d[e.u]+e.cost;
                    p[e.v]=G[u][i];
                    a[e.v]=min(a[u],e.cap-e.flow);
                    if(!inq[e.v])
                    {
                        q.push(e.v);
                        inq[e.v]=1;
                    }
                }
            }
        }
        if(d[T]==INF)return 0;
        flow+=a[T];
        cost+=(DB)a[T]*d[T];
        int U=T;
        while(U!=S)
        {
            edges[p[U]].flow+=a[T];
            edges[p[U]^1].flow-=a[T];
            U=edges[p[U]].u;
        }
        return 1;
    }
    DB mincost()
    {
        int flow=0;
        DB cost=0;
        while(SPFA(flow,cost));
        return cost;
    }
    bool check()
    {
        for(int i=0;i<edges.size();i++)
        {
            Edge& e=edges[i];
            if(e.u!=n+1&&e.v==T&&e.cap!=e.flow)
                return 0;
        }
        return 1;
    }
}Graph;
int main()
{
#ifndef ONLINE_JUDGE
    freopen("binary.in","r",stdin);
    freopen("binary.out","w",stdout);
#endif
    Read(n);
    for(int i=1;i<=n;i++)
        scanf("%lf %lf",&pot[i].X,&pot[i].Y); 
    sort(pot+1,pot+1+n,cmp);
    reverse(pot+1,pot+1+n);
    for(int i=1;i<=n;i++)
        for(int j=i+1;j<=n;j++)
            if(pot[i].Y>pot[j].Y)
                Graph.add(i,j+n,1,dis(pot[i],pot[j]));
    Graph.S=2*n+1,Graph.T=2*n+2;
    for(int i=1;i<=n;i++)
        Graph.add(Graph.S,i,2,0),
        Graph.add(i+n,Graph.T,1,0);
    DB ans=Graph.mincost();
    if(Graph.check())
        printf("%.10lf\n",ans);
    else
        cout<<-1<<endl;
}
發佈了99 篇原創文章 · 獲贊 1 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章