poj2031

8 篇文章 0 订阅
6 篇文章 0 订阅

题目不难,大致题意为:给定n个球中心的三维坐标,及半径。这些球中可能有相交的,也可能有相切的,也可能有相离。现要是的每个球都是相连的,相求相连的条件就是:

1)相切或相交

2)A->B,B->C则A->C即相连具有传递性和相互性(A->B<==>B->A)

3)A与B相离,在它们之间连一条线,注意线的长度为表面的连线长度。

对于相离的球,要求我们在它们之间连线,使得所有的球都是相连的,并求出所有连线的最小长度。

说白了,就是最小生成树算法。

但要注意几点:

1)相切或相连的球之间的距离为0

2)相离的球之间的距离为两球心的距离-两球的半径

3)注意精度问题,因为涉及到浮点数运算。那么判0问题要另设函数

然后就是kruskal算法或prim算法了。

下面是代码: 248K+16MS

#include<stdio.h>
#include<stdlib.h> //sort
#include<string.h> 
#include<math.h> // sqrt
#include<algorithm>  //qsort
#define Max 110
#define eps 1e-10 //最低精度
using namespace std;
struct Node{ // 记录距离
	int from;
	int to;
	double value;
}node[Max*Max];
struct Point{ // 记录球坐标及半径
	double x;
	double y;
	double z;
	double r;
}point[Max];
int set[Max];
int n;
bool cmp(Node p,Node q){ // sort 的 cmp 函数
	return p.value<q.value;
}
/*int cmp(const void *p,const void *q){ // qsort 的 cmp 函数 ,比较了一下,sort要快的多,毕竟qsort是c++标准函数库中的模板函数
	return (((Node*)p)->value>((Node*)q)->value)?1:-1; // 注意 qsort 与 sort 的cmp不同之处,前者为int,>0则排序,否则不排序,而后者为bool,true不排序,false排序
}*/
int find(int x){ // 查父节点
	int a=x,j;
	while(set[x]!=x)
		x=set[x];
	j=x;
	while(a!=j){ // 路径压缩
		int temp=set[a];
		set[a]=j;
		a=temp;
	}
	return x;
}
double Get_dis(Point a,Point b){ // 求出距离
   return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)+(a.z-b.z)*(a.z-b.z))-a.r-b.r;
}
int EPS(double x){ // 判0 函数
	if(fabs(x)<eps) // 将-eps——eps范围设置为‘0’,
		return 0;
	else if(x<0) //小于0
		return -1;
	else //大于0
		return 1;
}
int main(){
	while(scanf("%d",&n),n){
		int i,j;
		for(i=1;i<=n;i++)
			scanf("%lf%lf%lf%lf",&point[i].x,&point[i].y,&point[i].z,&point[i].r); // 输入顶点
		int pivot=0;
		for(i=1;i<=n;i++)
			for(j=i+1;j<=n;j++){
			   node[pivot].from=i,node[pivot].to=j; 
			   double temp=Get_dis(point[i],point[j]);
	           if(EPS(temp)<=0) // 若小于或等于0,则距离为0
				   node[pivot++].value=0.0;
			   else //若大于0
				   node[pivot++].value=temp;
			}
		for(i=1;i<=n;i++)
			set[i]=i;
		//qsort(node,pivot,sizeof(Node),cmp);
		sort(node,node+pivot,cmp); // 按距离从小到大排序
		double Sum=0.0; // 总长度
		for(i=0;i<pivot;i++){
			int x=find(node[i].from); //查父节点
			int y=find(node[i].to);
			if(x!=y){ // 并父节点,大并小
				Sum+=node[i].value; // 增加这条边,长度相应增加
				if(x>y)
					set[x]=y;
				else
					set[y]=x;
			}
			
		}
		printf("%.3lf\n",Sum); // 输出最小生成树长度
	}
	return 0;
}
		
	


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值