最小生成树的题目,需要先理解一下东西,
先说下题目大意:输入一个n,表示下面有n组数据,每组数据表示一个球,题目上称之为cell。分别为x,y,z,r,表示球心坐标跟球的半径。
你要在空间站内修一些通道,使得所有的cell都连通,要求是通道的长度要最短,其实就是个最小生成树,然后要特出处理的就是这些cell有可能本身就是相连接的,然后要预先把相连通的子图压缩成一个点,求其他点到这个子图中所有点的最短距离为一条树边,要注意的这个距离为两球面间的距离来判断,
方法就是这些,算是简单的计算几何跟最小生成树的结合吧,可以很好的练一练,会用到一些简单的三维计算几何的东西。
还有一点要注意的是提交的时候G++要用%f来提交,记得看一个博客是说好像浮点数标准的就是%f 而不是%lf,这里wrong了一次...多组数据记得初始化,没有初始化又wrong了一次。。。
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<string>
#include<vector>
using namespace std;
const double eps = 1e-8;
const int N = 110;
int dcmp(double x)/*判断浮点数*/
{
if(fabs(x) < eps)
{
return 0;
}
else
{
return x < 0 ? -1 : 1 ;
}
}
struct Point
{
double x,y,z;
Point(const double& x = 0,const double& y = 0,const double& z = 0):x(x),y(y),z(z) {}
Point(const Point& res)
{
(*this).x = res.x;
(*this).y = res.y;
(*this).z = res.z;
}
};
struct Cell:public Point{/*重载Point得到球*/
//Point point;
double R;
Cell() {}
Cell( const Point& res,const double& r):Point(res),R(r) {}
};
struct Edge
{
int from,to;
double dis;
Edge(const int& from =0 ,const int& to = 0,const double& dis = 0):from(from),to(to),dis(dis){}
bool operator < (const Edge& res) const
{
return (*this).dis < res.dis;
}
};
typedef Point Vector;
Vector operator - (Vector A , Vector B)
{
return Vector(A.x - B.x , A.y - B.y , A.z - B.z);
}
Vector operator + (Vector A , Vector B)
{
return Vector(A.x + B.x , A.y + B.y , A.z + B.z);
}
Vector operator * (Vector A, double p)
{
return Vector(A.x * p, A.y * p,A.z * p);
}
Vector operator / (Vector A, double p)
{
return Vector(A.x / p , A.y / p ,A.z / p);
}
double Dot(Vector A , Vector B)
{
return A.x * B.x + A.y * B.y + A.z * B.z;
}
Vector Cross(Vector A, Vector B)
{
return Vector( A.y*B.z - A.z*B.y , A.z* B.z - A.x*B.z ,A.x*B.y - A.y*B.x);
}
double Length(Vector A)
{
return sqrt(Dot(A,A));
}
int root[N];
void InitSet(int n)
{
for(int i = 1 ; i <= n ; i++)
{
root[i] = i;
}
}
int FindSet(int x)
{
if( x != root[x])
{
root[x] = FindSet(root[x]);
}
return root[x];
}
void UnionSet(int a,int b)
{
int x = FindSet(a);
int y = FindSet(b);
if( x != y)
{
root[x] = y;
}
}
vector<Edge>edge;
void MST()
{
double ans = 0;
for(int i = 0 ; i < edge.size() ; i++)
{
int from = edge[i].from;
int to = edge[i].to;
double dis = edge[i].dis;
if(FindSet(from) != FindSet(to))
{
ans += dis;
UnionSet(from,to);
}
}
printf("%.3f\n",ans);
}
int main()
{
#ifdef LOCAL
freopen("in.txt","r",stdin);
#endif // LOCAL
int n;
vector<Cell>cell;
while(scanf("%d",&n) && n)
{
edge.clear();
cell.clear();
double x,y,z,r;
for(int i = 0 ; i < n ; i++)
{
scanf("%lf %lf %lf %lf",&x,&y,&z,&r);
cell.push_back(Cell(Point(x,y,z),r));
}
InitSet(n);
for(int i = 0 ; i < n ; i++)
{
for(int j = i + 1 ; j < n ; j++)
{
if( dcmp(Length((Point)cell[i] - (Point)cell[j]) - (cell[i].R + cell[j].R)) <= 0 )
{
UnionSet(i+1,j+1);
}
}
}
for(int i = 0 ; i < n ; i++)
{
for(int j = i+1 ; j < n ; j++)
{
if( FindSet(i+1) != FindSet(j+1))
{
double dis = Length((Point)cell[i] - (Point)cell[j]) - (cell[i].R + cell[j].R);
// cout<<dis<<endl;
edge.push_back(Edge(FindSet(i+1),FindSet(j+1),dis));
}
}
}
sort(edge.begin(),edge.end());
MST();
}
return 0;
}