随笔- 22  文章- 0  评论- 10  阅读- 1579 

[CF277E]Binary Tree on Plane

题意

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

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

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

思路

题目给出了对每个点的度数的限制,并且父亲和孩子不能随便取,考虑费用流。

把每个点拆成两个点 p1p2,分别代表入点和出点。由于每个点最多只能有两个子节点,所以从源点向 p1 连一条容量为 2 ,费用为 0 的边;由于每个点只有一个父节点,所以从 p2 向汇点连一条容量为 1 ,费用为 0 边。同时,如果一个点能连向另一个点,就从该点的 p1 向那个点的 p2 连一条容量为 1,费用为这两点之间的距离 len 的边。最后从源点到汇点跑费用流即可。

代码

#include<bits/stdc++.h>
#define MAXN 410
#define INF 2000000000
using namespace std;
int n,s,t;
struct point
{
    int x,y;
}po[MAXN];
bool cmp(point a,point b)
{
    return a.y<b.y;
}
struct edge
{
    int to,from,nxt,w;
    double c;
}ed[MAXN*MAXN];
int head[MAXN],tot=1;
void add(int u,int v,int w,double c)
{
    ed[++tot].to=v;
    ed[tot].w=w;
    ed[tot].c=c;
    ed[tot].from=u;
    ed[tot].nxt=head[u];
    head[u]=tot;
}
int pre[MAXN],vis[MAXN],flo[MAXN];
int arr[MAXN],up=0,down=0,now;
int flow;
double cost;
double dis[MAXN];
bool spfa()
{
    up=down=0;
    arr[++down]=s;
    for(int i=0;i<=n*2+1;i++)
        dis[i]=INF;
    dis[s]=0;
    vis[s]=1;
    flo[s]=INF;
    while(up<down)
    {
        now=arr[++up];
        vis[now]=0;
        for(int i=head[now];i;i=ed[i].nxt)
        {
            int v=ed[i].to;
            double c=ed[i].c;
            if(!ed[i].w)continue;
            if(dis[v]>dis[now]+c)
            {
                dis[v]=dis[now]+c;
                flo[v]=min(flo[now],ed[i].w);
                pre[v]=i;
                if(!vis[v])
                {
                    vis[v]=1;
                    arr[++down]=v;
                }
            }
        }
    }
    if(dis[t]<INF)return true;
    else return false;
}
void costflow()
{
    flow=cost=0;
    int now,last;
    while(spfa())
    {
        flow+=flo[t];
        cost+=dis[t];
        now=t;
        while(now!=s)
        {
            last=pre[now];
            ed[last].w-=flo[t];
            ed[last^1].w+=flo[t];
            now=ed[last].from;
        }
    }
}
double getdis(point a,point b)
{
    return sqrt((a.x-b.x+0.0)*(a.x-b.x+0.0)+(a.y-b.y+0.0)*(a.y-b.y+0.0));
}
int main()
{
    scanf("%d",&n);
    s=0;
    t=2*n+1;
    for(int i=1;i<=n;i++)
        scanf("%d%d",&po[i].x,&po[i].y);
    sort(po+1,po+n+1,cmp);
    for(int i=1;i<=n;i++)
    {
        add(s,i,2,0);
        add(i,s,0,0);
        add(i+n,t,1,0);
        add(t,i+n,0,0);
        for(int j=1;j<i;j++)
        {
            if(po[j].y<po[i].y)
            {
                add(i,j+n,1,getdis(po[i],po[j]));
                add(j+n,i,1,-getdis(po[i],po[j]));
            }
        }
    }
    costflow();
    if(flow==n-1)printf("%lf",cost);
    else printf("-1");
    return 0;
}
 posted on   hu_led  阅读(20)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示