poj2031:http://poj.org/problem?id=2031
题意:就是给出三维坐标系上的一些球的球心坐标和其半径,搭建通路,使得他们能够相互连通。如果两个球有重叠的部分则算为已连通,无需再搭桥。求搭建通路的最小费用(费用就是边权,就是两个球面之间的距离)。
题解:其实就是图论的最小生成树问题球心坐标和半径是用来求 两点之间的边权 的,求出边权后,把球看做点,用邻接矩阵存储这个无向图,再求最小生成树,非常简单的水题把球A和球B看做无向图图的两个结点,那么边权 = AB球面距离 = A球心到B球心的距离 – A球半径 – B球半径 .注意若边权<=0,说明两球接触,即已连通,此时边权为0
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<algorithm> 5 #include<cmath> 6 using namespace std; 7 int n,pa[102],num,cnt; 8 struct Edge{ 9 int u; 10 int v; 11 double w; 12 bool operator <(const Edge &a)const{ 13 return w<a.w; 14 } 15 }edge[5000]; 16 struct Node{ 17 double x; 18 double y; 19 double z; 20 double r; 21 }node[102]; 22 void UFset(){ 23 for(int i=1;i<=n;i++) 24 pa[i]=-1; 25 } 26 int Find(int x){ 27 int s; 28 for(s=x;pa[s]>=0;s=pa[s]); 29 while(s!=x){ 30 int temp=pa[x]; 31 pa[x]=s; 32 x=pa[x]; 33 } 34 return s ; 35 } 36 void Union(int R1,int R2){ 37 int r1=Find(R1); 38 int r2=Find(R2); 39 int temp=pa[r1]+pa[r2]; 40 if(pa[r1]>pa[r2]){ 41 pa[r1]=r2; 42 pa[r2]=temp; 43 } 44 else{ 45 pa[r2]=r1; 46 pa[r1]=temp; 47 } 48 } 49 void kruska(){ 50 UFset(); 51 num=0; 52 double sum=0.0; 53 for(int i=1;i<cnt;i++){ 54 int u=edge[i].u; 55 int v=edge[i].v; 56 if(Find(u)!=Find(v)){ 57 sum+=edge[i].w; 58 Union(u,v); 59 num++; 60 } 61 if(num>=n-1)break; 62 } 63 printf("%.3f ",sum); 64 } 65 int main(){ 66 while(~scanf("%d",&n)&&n){ 67 for(int i=1;i<=n;i++){ 68 scanf("%lf%lf%lf%lf",&node[i].x,&node[i].y,&node[i].z,&node[i].r); 69 } 70 cnt=1; 71 for(int i=1;i<=n;i++) 72 for(int j=i+1;j<=n;j++){ 73 double s1=node[i].x-node[j].x; 74 double s2=node[i].y-node[j].y; 75 double s3=node[i].z-node[j].z; 76 double ss=sqrt(s1*s1+s2*s2+s3*s3); 77 if(ss>node[i].r+node[j].r){ 78 edge[cnt].u=i;edge[cnt].v=j;edge[cnt++].w=ss-node[i].r-node[j].r; 79 } 80 else{ 81 edge[cnt].u=i;edge[cnt].v=j;edge[cnt++].w=0; 82 } 83 } 84 85 sort(edge+1,edge+cnt); 86 kruska(); 87 } 88 }