POJ 2031 Building a Space Station (最小生成树,裸题)

62 篇文章 0 订阅

题目意思:
给你n个球体,输入n,接下俩输入n行中每行有四个数,分别代表球的球心坐标x,y,z 和球径r 。
可以在两球之间建立通道,现在要将所有球体联通,求最小代价。

本题要点:
1、 两个球体 (x1, y1, z1, r1) 和 (x2, y2, z2, r2) 球的表面之间的距离:
d = sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2) + (z1 - z2) * (z1 - z2)) - r1 - r1;
如果d < 0 (此时,球有相交的情况), 另 d = 0
2、 然后就是很裸的最小生成树的问题, 用 prim 算法套模板。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <cmath>
using namespace std;
const int MaxN = 110;
int n;
double a[MaxN][MaxN], d[MaxN], ans;
bool vis[MaxN];

struct Station
{
	double x, y, z, r;
}s[MaxN];

void prim()
{
	for(int i = 1; i <= n; ++i)
	{
		d[i] = 1e9;
	}
	memset(vis, false, sizeof vis);
	d[1] = 0;
	for(int i = 1; i < n; ++i)
	{
		int x = 0;
		for(int j = 1; j <= n; ++j)
		{
			if(!vis[j] && (0 == x || d[j] < d[x]))
			{
				x = j;		
			}
		}
		vis[x] = 1;
		for(int y = 1; y <= n; ++y)
		{
			if(!vis[y])
			{
				d[y] = min(d[y], a[x][y]);
			}
		}
	}
	ans = 0;
	for(int i = 1; i <= n; ++i)
	{
		ans += d[i];
	}
	printf("%.3f\n", ans); // %lf 输出会wa, 改为 %f 输出
}

int main()
{
	while(scanf("%d", &n) && n)
	{
		for(int i = 1; i <= n; ++i)
		{
			scanf("%lf%lf%lf%lf", &s[i].x, &s[i].y, &s[i].z, &s[i].r);
		}
		for(int i = 1; i <= n; ++i)
			for(int j = 1; j <= n; ++j)
			{
				a[i][j] = 1e9;
			}
		double x1, y1, z1, r1, x2, y2, z2, r2;
		for(int i = 1; i <= n; ++i)
		{
			for(int j = i + 1; j <= n; ++j)
			{
				x1 = s[i].x, y1 = s[i].y, z1 = s[i].z, x2 = s[j].x, y2 = s[j].y, z2 = s[j].z;
				r1 = s[i].r, r2 = s[j].r;
				a[i][j] = a[j][i] = sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2) + (z1 - z2) * (z1 - z2)) - r1 - r2;
				if(a[i][j] < 0)
				{
					a[i][j] = a[j][i] = 0;
				}
			}
		}
		prim();
	}
	return 0;
}

/*
3
10.000 10.000 50.000 10.000
40.000 10.000 50.000 10.000
40.000 40.000 50.000 10.000
2
30.000 30.000 30.000 20.000
40.000 40.000 40.000 20.000
5
5.729 15.143 3.996 25.837
6.013 14.372 4.818 10.671
80.115 63.292 84.477 15.120
64.095 80.924 70.029 14.881
39.472 85.116 71.369 5.553
0
*/

/*
20.000
0.000
73.834
*/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值