Description:
在二维平面内有一些点,求任意三个点使他们的两两距离之和最小。
Input:
第一行一个正整数n
接下来n行每行两个整数xi,yi,表示第i个点的坐标
Output:
一行一个数表示最小距离和,保留6位小数。
思路:
和求最近点对一样啊
只是多枚举一个点计算两两距离之和而已
但是还是有很多容易错的地方啊
CODE:
View Code1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include<algorithm> 5 #define R register 6 #define go(i,a,b) for(R int i=a;i<=b;i++) 7 #define ll long long 8 #define db long double 9 #define M 200000+1 10 #define inf 2e50 // inf不能太小了 11 using namespace std; 12 int read() 13 { 14 int x=0,y=1;;char c=getchar(); 15 while(c<'0'||c>'9') {if(c=='-') y=-1;c=getchar();} 16 while(c>='0'&&c<='9') {x=(x<<3)+(x<<1)+c-'0';c=getchar();} 17 return x*y; 18 } 19 int n; 20 struct node{int x,y;}a[M],b[M]; 21 bool cmp1(node x,node y){return x.x==y.x?x.y<y.y:x.x<y.x;} 22 db cl(node x,node y){return (db)sqrt((ll)(x.x-y.x)*(x.x-y.x)+(ll)(x.y-y.y)*(x.y-y.y));}//注意这里的(ll) 23 db sol(int l,int r) 24 { 25 if(l+1>=r) {if(a[l].y>a[r].y) swap(a[l],a[r]);return inf;} 26 //注意上面 因为用的是归并排序,必须要保持序列按y递增 27 int mid=(l+r)>>1,midx=a[mid].x; 28 db ans=min(sol(l,mid),sol(mid+1,r)); 29 //--------------- 30 int l1=l,r1=mid+1,ct=0; 31 while(l1<=mid&&r1<=r) 32 { 33 if(a[l1].y<=a[r1].y) b[++ct]=a[l1],l1++; 34 else b[++ct]=a[r1],r1++; 35 } 36 while(l1<=mid) b[++ct]=a[l1],l1++; 37 while(r1<=r) b[++ct]=a[r1],r1++; 38 ct=0; 39 go(i,l,r) a[i]=b[++ct]; 40 //---------------归并排序 41 ct=0; 42 go(i,l,r) if(abs((db)a[i].x-midx)<ans) b[++ct]=a[i]; 43 go(x,1,ct) 44 go(y,x+1,ct) 45 { 46 if(b[y].y-b[x].y>=ans) break; 47 go(z,y+1,ct) 48 { 49 if(b[z].y-b[y].y>=ans) break; 50 ans=min(ans,cl(b[x],b[y])+cl(b[x],b[z])+cl(b[y],b[z])); 51 } 52 } 53 return ans; 54 } 55 int main() 56 { 57 freopen("math.in","r",stdin); 58 freopen("math.out","w",stdout); 59 n=read(); 60 go(i,1,n) a[i].x=read(),a[i].y=read(); 61 sort(a+1,a+n+1,cmp1); 62 printf("%.6Lf",sol(1,n)); 63 return 0; 64 }