2019 UESTC ACM Training for Graph[O] (最优比例生成树)

题意:空间中内有n个点,连n-1条边,使得这些边 的高度差之和比上水平距离之和最小。

最优比例生成树问题
对于一个最小生成树,可以表达为如下形式:
x1 * a1+x2 * a2+…+xm * am
其中x1 ~ xm要么为1要么为0,并且xi的和为n-1。ai是编号为i的边的权值,并且选择的点要使得图联通。
那么对于题中的问题,取一个生成树满足sum{xi * hi}/sum{xi * di}>=ans
对上式变形,得到:
sum{xi * (hi-ans * di)}>=0
很显然,这就是普通的最小生成树的形式,每条边的边权为hi-ans * di,并且由于ans有单调性,二分ans然后求最小生成树,然后判断最小生成树的和是否大于零,然后卡左右边界的值即可。
但是二分的方法会超时。因此考虑使用迭代的方法解决。
假设当前讨论到的答案是x,那么每条边的边权为hi-x * di。用变量x0记录之前算出的答案x,然后跑最小生成树,记录sumh,sumd为这次最小生成树中高度差的和以及水平距离的和,然后用sumh/sumd当作新的x值进行迭代计算。直到x和x0相比不再变小,就可以停止迭代了。
这种算法的正确性建立在x的每次迭代和上次相比会单调递减。更具体的分析参考博客:https://blog.csdn.net/chenzhenyu123456/article/details/48160209

#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<stack>
#include<vector>
#include<cmath>
#include<map>
#define LL long long
using namespace std;
const int maxn=1005;
const double inf=1e10;
const double eps=1e-4;
inline void _read(int &x){
    char t=getchar();bool sign=true;
    while(t<'0'||t>'9')
    {if(t=='-')sign=false;t=getchar();}
    for(x=0;t>='0'&&t<='9';t=getchar())x=x*10+t-'0';
    if(!sign)x=-x;
}
int n,fa[maxn];
double x[maxn],y[maxn],z[maxn];
int getfa(int a){return a==fa[a]?a:fa[a]=getfa(fa[a]);}
struct Edge{
	int from,to;
	double d,h,dis;
	Edge(int from,int to,double d,double h,double dis):from(from),to(to),d(d),h(h),dis(dis){}
	bool operator <(const Edge& red)const{
		return dis < red.dis;
	}
};
vector<Edge>edges;
void addedges(int from,int to,double d,double h){
	edges.push_back(Edge(from,to,d,h,0));
}
double get_dist(int i,int j){
	return sqrt((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]));
}
int main(){
	_read(n);
	for(int i=1;i<=n;i++)cin>>x[i]>>y[i]>>z[i];
	for(int i=1;i<n;i++)
		for(int j=i+1;j<=n;j++)
			addedges(i,j,get_dist(i,j),fabs(z[i]-z[j]));
	double cur=0,ans=inf;
	while(1){
		for(int i=1;i<=n;i++)fa[i]=i;
		for(int i=0;i<edges.size();i++)edges[i].dis=edges[i].h-edges[i].d*cur;
		sort(edges.begin(),edges.end());
		double sum1=0,sum2=0,sum=0;
		for(int i=0;i<edges.size();i++){
			int u=edges[i].from,v=edges[i].to;
			int fu=getfa(u),fv=getfa(v);
			if(fu!=fv)fa[fu]=fv,sum+=edges[i].dis,sum1+=edges[i].h,sum2+=edges[i].d;
		}
		cur=sum1/sum2;
		if(fabs(cur-ans)<=eps)break;
		ans=cur;
	}
	printf("%.3lf",ans);
}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
互联网络程序设计是指在互联网上进行程序开发和设计的过程。UESTC则是我国的一所著名高校——电子科技大学。 互联网络程序设计 uestc包含了两个主要的方面:互联网络和程序设计。互联网络是指将多个计算机网络通过通信链路互相连接起来,实现信息共享和资源共享的网络系统。程序设计是指根据需求和目标,通过编写代码和设计算法,实现计算机程序的过程。 互联网络程序设计 uestc的学习内容主要包括以下几个方面: 1. 网络知识:学习互联网络的基本概念、原理和协议,如TCP/IP协议、HTTP协议等。掌握网络编程的基本技术,能够编写网络应用程序。 2. 数据通信:学习数据通信的基本原理和技术,包括数据传输的方式、数据压缩和加密等。了解网络安全和数据保护的基本知识。 3. 程序设计:学习编程语言和开发工具,如Java、C++和Python等。掌握常用的编程技巧和方法,能够设计和实现复杂的网络应用程序。 4. Web开发:学习Web开发的基本知识和技术,包括HTML、CSS、JavaScript等。能够设计和实现交互式的Web应用程序。 5. 数据库技术:学习数据库的基本原理和技术,如SQL语言和数据库管理系统。能够设计和管理数据库,实现数据的存储和检索。 通过学习互联网络程序设计 uestc,可以掌握互联网应用开发的基本技能,具备设计和实现网络应用程序的能力。这对于目前互联网行业的人才需求来说是非常重要的,也为学生提供了广阔的就业和创业机会。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值