CF277E Binary Tree on Plane

Posted henryhuang-never-settle

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CF277E Binary Tree on Plane相关的知识,希望对你有一定的参考价值。

CF277E Binary Tree on Plane

题目大意

给定平面上的 (n) 个点,定义两个点之间的距离为两点欧几里得距离,求最小二叉生成树。

题解

妙啊。

难点在于二叉的限制。

注意到二叉树每一个点最多有一个父亲,最多可以有两个儿子,这让我们联想到了网络流中的容量。

考虑建图:

令源点为 (s),汇点为 (t)

我们将每一个点 (u) 拆为两个点 (u_1,u_2);

每个点最多可以有两个儿子 (Rightarrow)(s)(u_1) 连一条容量为 (2),费用为 (0) 的边。

每个点最多可以有一个父亲 (Rightarrow)(u_2)(t) 连一条容量为 (1),费用为 (0) 的边。

(u) 可以成为 (v) 的父亲 (Rightarrow)(u_1)(v_2) 连一条容量为 (1),费用为 (operatorname{dist}(u,v)) 的边。

然后我们跑最小费用最大流,判断最大流是否为 (n-1) 即可。

/*---Author:HenryHuang---*/
#include<bits/stdc++.h>
#define eps 1e-6
using namespace std;
const int maxn=800+5;
typedef long long ll;
struct edge{
	int to,nex,w;
	double v;
}e[maxn*maxn*2];
int head[maxn],cur[maxn],tot=1;
void add(int a,int b,int c,double d){
	e[++tot]=(edge){b,head[a],c,d};
	head[a]=cur[a]=tot;
}
void addedge(int a,int b,int c,double d){
	add(a,b,c,d);
	add(b,a,0,-d);
}
int n,m,s,t;
double dis[maxn];
bool vis[maxn];
bool spfa(){
	memset(vis,0,sizeof vis);
	for(int i=s;i<=t;++i) vis[i]=0,dis[i]=(1ll<<60),cur[i]=head[i];
	queue<int> Q;
	dis[s]=0;vis[s]=1;Q.push(s);
	while(!Q.empty()){
		int u=Q.front();Q.pop();
		vis[u]=0;
		for(int i=head[u];i;i=e[i].nex){
			int v=e[i].to;
			if(e[i].w&&dis[v]-dis[u]-e[i].v>eps){
				dis[v]=dis[u]+e[i].v;
				if(!vis[v]) vis[v]=1,Q.push(v);
			}
		}
	}
	return dis[t]<(double)(1ll<<60);
}
int dfs(int u,int in){
	if(u==t) return in;
	int out=0,tmp;
	vis[u]=1;
	for(int i=cur[u];i;i=e[i].nex){
		int v=e[i].to;cur[u]=i;
		if((!vis[v])&&e[i].w&&abs(dis[v]-dis[u]-e[i].v)<eps&&(tmp=dfs(v,min(in,e[i].w)))){
			e[i].w-=tmp,e[i^1].w+=tmp;
			in-=tmp,out+=tmp;
			if(!in) break;
		}
	}
	if(!out) dis[u]=0;
	vis[u]=0;
	return out;
}
double x[maxn],y[maxn];
int main(){
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	cin>>n;
	for(int i=1;i<=n;++i) cin>>x[i]>>y[i];
	s=0,t=2*n+1;
	for(int i=1;i<=n;++i) addedge(s,i,2,0),addedge(i+n,t,1,0);
	for(int i=1;i<=n;++i)
		for(int j=1;j<=n;++j)
			if(i!=j&&y[i]>y[j]) addedge(i,j+n,1,sqrt((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j])));
	int ans1=0;double ans2=0;	
	while(spfa()){
		int tmp=dfs(s,2e9);
		ans2+=dis[t]*tmp;
		ans1+=tmp;
	}
	if(ans1==n-1) cout<<setprecision(6)<<fixed<<ans2<<‘
‘;
	else cout<<-1<<‘
‘;
	return 0;
}

以上是关于CF277E Binary Tree on Plane的主要内容,如果未能解决你的问题,请参考以下文章

题解CF277E Binary Tree on Plane

CF438E The Child and Binary Tree

CF438E The Child and Binary Tree

CF438E The Child and Binary Tree——生成函数

CF1311E Construct the Binary Tree

[CF750G]New Year and Binary Tree Paths