• 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;
    }
    
  • 相关阅读:
    Python机器学习算法 — 关联规则(Apriori、FP-growth)
    Python数据存储 — MySQL数据库操作
    Python机器学习算法 — 朴素贝叶斯算法(Naive Bayes)
    七大查找算法(Python)
    react-redux源码学习
    理解webpack4.splitChunks
    redux、immutablejs和mobx性能对比(一)
    前端初探 Gitlab CI/CD
    React SPA 应用 hash 路由如何使用锚点
    理解webpack4.splitChunks之其余要点
  • 原文地址:https://www.cnblogs.com/HenryHuang-Never-Settle/p/solution-CF277E.html
Copyright © 2020-2023  润新知