[CF277E]Binary Tree on Plane
题意
给你平面上 \(n\) 个点 (\(2 \leq n \leq 400\)),要求用这些点组成一个二叉树(每个节点的儿子节点不超过两个),定义每条边的权值为两个点之间的欧几里得距离。求一个权值和最小的二叉树,并输出这个权值。
其中,点 \(i\) 可以成为点 \(j\) 的的父亲的条件是:点 \(i\) 的 \(y\) 坐标比 \(j\) 的 \(y\) 坐标大。
如果不存在满足条件的二叉树,输出 \(-1\) 。
思路
题目给出了对每个点的度数的限制,并且父亲和孩子不能随便取,考虑费用流。
把每个点拆成两个点 \(p1\) 和 \(p2\),分别代表入点和出点。由于每个点最多只能有两个子节点,所以从源点向 \(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;
}