poj2031 - Building a Space Station

                                  想看更多的解题报告: http://blog.csdn.net/wangjian8006/article/details/7870410
                                  转载请注明出处:http://blog.csdn.net/wangjian8006

题目大意:给定一些个球的圆心与半径,如果两个球之间相交,则他们之间连通,否则不连通,问还需要连多长的边使所有球都连通

 

解题思路:一个已存在边的最小生成树,只不过题目太难读了,任意两个球,如果连通则边权为0,否则边权为d-r1-r2,d是两球圆心坐标之间的距离,r1与r2分别为两个球的半径,这样求一个最小生成树,将所有球连接起来

/*
Memory 280K
Time   16MS
*/
#include <iostream>
#include <math.h>
using namespace std;
#define MAXV 105
#define INF 10e8

typedef struct{
	double x,y,z,r;
}QIU;

QIU q[MAXV];
int n;
double map[MAXV][MAXV];

double distance(int i,int j){
	double x=q[i].x-q[j].x;
	double y=q[i].y-q[j].y;
	double z=q[i].z-q[j].z;
	return sqrt(x*x+y*y+z*z);
}

double cross(int i,int j){
	double r=q[i].r+q[j].r;
	double d=distance(i,j);
	if(d>r) return d-r;
	return 0;
}

void prim(){
	int i,j,v;
	double d[MAXV];
	bool vis[MAXV];
	for(i=1;i<=n;i++){
		d[i]=map[1][i];
		vis[i]=0;
	}

	for(i=1;i<=n;i++){
		double min=INF;
		for(j=1;j<=n;j++)
			if(!vis[j] && d[j]<min){			//找最小点加进来
				min=d[j];
				v=j;
			}
		
		vis[v]=1;
		
		for(j=1;j<=n;j++){
			if(!vis[j] && map[v][j]<d[j])		//取邻边的最小边
				d[j]=map[v][j];
		}
	}
	for(d[0]=0,i=1;i<=n;i++) d[0]+=d[i];
	printf("%.3lf\n",d[0]);
}

int main(){
	freopen("d:\\test.in","r",stdin);
	int i,j;
	while(~scanf("%d",&n) && n){
		for(i=1;i<=n;i++){
			scanf("%lf%lf%lf%lf",&q[i].x,&q[i].y,&q[i].z,&q[i].r);
		}
		memset(map,0,sizeof(map));
		for(i=1;i<=n;i++){
			for(j=i+1;j<=n;j++){
				map[i][j]=map[j][i]=cross(i,j);
			}
		}

		prim();
	}
	return 0;
}


 

你可能感兴趣的:(struct,distance)