1. 程式人生 > >POJ2031 Building a Space Station【最小生成樹】

POJ2031 Building a Space Station【最小生成樹】

col lap ret stream 坐標系 ide 最小 過程 如果

題意:

就是給出三維坐標系上的一些球的球心坐標和其半徑,搭建通路,使得他們能夠相互連通。如果兩個球有重疊的部分則算為已連通,無需再搭橋。求搭建通路的最小邊長總和是多少。

思路:

先處理空間點之間的距離,要註意的是兩個球面相交的情況,相交的話距離是0。兩球面距離是球心距離減去兩個球的半徑(邊權 = AB球面距離 = A球心到B球心的距離 – A球半徑 – B球半徑),相交時距離是算出來是負值,要改為0。其實就是求連接所有球最小生成樹的過程。

代碼:

kruskal:

技術分享
#include <iostream>
#include <cstdio>
#include <algorithm>
#include 
<cmath> using namespace std; int n; double need; struct Station //定義球的結構體 { double x,y,z; double r; }; Station station[110]; struct Vdge //構造生成樹的點 { int x,y; double l; }; bool cmp(Vdge a,Vdge b){ return a.l < b.l ; } Vdge edge[5500]; int road[110]; int find(int x) {
while( x != road[x] ) x = road[x]; return x; } bool judge(int x,int y){ int fx = find(x); int fy = find(y); if( fx==fy ) return false; else { road[fx] = fy; return true; } } double dis(int i,int j) { double distance; double a = pow(station[i].x-station[j].x , 2
); double b = pow(station[i].y-station[j].y , 2); double c = pow(station[i].z-station[j].z , 2); distance = sqrt(a+b+c); distance -= station[i].r + station[j].r; if( distance <= 0 ) distance = 0; return distance; } void init() { for(int i=0 ; i<n ; i++) scanf("%lf %lf %lf %lf",&station[i].x,&station[i].y,&station[i].z,&station[i].r); for(int i=0 ; i<n ; i++) road[i] = i; need = 0; int k = 0; for(int i=0 ; i<n ; i++) { for(int j=0 ; j<n ; j++) { if( j>i ) { edge[k].x = i; edge[k].y = j; edge[k].l = dis(i,j); k++; } } } sort(edge,edge+n*(n-1)/2,cmp); } void kruskal() { int i=0,j=0; while( i<n-1 ) { if( judge(edge[j].x,edge[j].y) ) need += edge[j].l , i++; j++; } } int main() { while(cin>>n,n) { init(); kruskal(); printf("%.3f\n",need ); } return 0; }
View Code

POJ2031 Building a Space Station【最小生成樹】