S中的点为平面上的点,将平面上的点集分割为点的个数大致相同的两个子集S1和S2,选取垂直线x=c来作为分割线,其中,m为S中各点x坐标的中位数。遵循分治法方法,我们可以递归求出左子集S1和右子集S2中的最近对。设d1和d2分别是S1和S2点对中的最小距离,因为距离最近的两个点可能位于分界线的两侧。所以,在合并较小子问题的解时,需要增加一个步骤来检查是否存在这样的点。显然,我们把这种尝试限制在以x=c为对称的、宽度为2d(d1和d2中的最小值)的垂直带中。
设S1和S2分别是该垂直带左右部分的点构成的子集。现在,对于S1中的,每个点P(x,y),需要检查S2中的点和P之间的距离是否小于d。这种点的y轴坐标一定位于区间[y-d,y+d]中,这样的点最多为6个,因为S2中的点相互之间的距离至少为d。S1和S2中的点按照y坐标升序排序,所以每次迭代时对这些点不必重新排序,只要合并两个已经排好序的集合就可以了。我们可以顺序地处理S1中的点,同时使用一个指针在S2中的宽度为2d的区间中来回移动,取出6个候选点,来计算它们和S1当前点p之间的距离,找到与之距离小于d的点,更新最短距离,直到循环结束,即可求出最短距离。
package 实验二;
public class 最近对问题_分治法 {
public static void main(String args[]) {
分治 fz=new 分治();
fz.init(); //随机点
fz.showxy();
fz.initSortX(); //按X轴排序
fz.showxy2();
fz.zhongjianshu(); //找中间数
fz.min1(); //找min1
fz.min2(); //找min2
fz.compare(); //min1和min2最小的
fz.SS1();
fz.SS2();
//如果S1或S2有空的,那么最近点肯定在S1或S2中
if(fz.countSS1==0 || fz.countSS2==0) {
double min000=fz.min1<fz.min2?fz.min1:fz.min2;
if(min000==fz.min1) {
System.out.print("最近点为:");
System.out.print("("+fz.xy[fz.min1_i_1].x+","+fz.xy[fz.min1_i_1].y+")"+" ");
System.out.print("("+fz.xy[fz.min1_i_2].x+","+fz.xy[fz.min1_i_2].y+")"+" ");
System.out.println();
}
if(min000==fz.min2) {
System.out.print("最近点为:");
System.out.print("("+fz.xy[fz.min2_i_1].x+","+fz.xy[fz.min2_i_1].y+")"+" ");
System.out.print("("+fz.xy[fz.min2_i_2].x+","+fz.xy[fz.min2_i_2].y+")"+" ");
System.out.println();
}
}
//
//
//
else {
fz.initSortSS1Y(); //对SS1的Y轴排序
fz.initSortSS2Y(); //对SS2的Y轴排序
fz.min3(); //找第三个最近点
fz.Min(); //找所有的最近点
}
}
}
class X_Y {
double x;
double y;
}
class 分治{
int length=30;
X_Y[] xy=new X_Y[length];
X_Y[] xy2=new X_Y[length];
X_Y[] SS1;
X_Y[] SS2;
X_Y[] SS1_2;
X_Y[] SS2_2;
X_Y[] xy4;
double m=0; //中间数
int mi=0; //中间数的下标
double min1=999; //S1的最近点
int min1_i_1; //S1的最近点的下标1
int min1_i_2; //S1的最近点的下标2
double min2=999; //S2的最近点
int min2_i_1; //S2的最近点的下标1
int min2_i_2; //S2的最近点的下标2
double min=999; //S1与S2中最近的点
double min3=999; //
int min3_i_1; //3的最近点的下标1
int min3_i_2; //3的最近点的下标2
int min_1; //所有最近点1
int min_2; //所有最近点2
int countSS1=0;
int countSS2=0;
/
//初始化
/
void init() {
for(int i=0;i<length;i++) {
xy[i]=new X_Y();
xy2[i]=new X_Y();
xy[i].x=(int)(Math.random()*30);
xy[i].y=(int)(Math.random()*30);
}
}
void showxy() {
for(int i=0;i<length;i++) {
System.out.print("("+xy[i].x+","+xy[i].y+")"+" ");
}
System.out.println();
}
void showxy2() {
for(int i=0;i<length;i++) {
xy[i]=xy2[i];
System.out.print("("+xy[i].x+","+xy[i].y+")"+" ");
}
System.out.println();
}
//
//分治排序,按X轴排序
//
void initSortX(){
MergeSortX(xy,xy2,0,length-1);
}
void MergeSortX(X_Y xy[],X_Y xy2[],int s,int t){
int m;
if(s==t)
xy2[s]=xy[s];
else {
m=(s+t)/2;
MergeSortX(xy,xy2,s,m); //归并前半个子序列
MergeSortX(xy,xy2,m+1,t); //归并后半个子序列
MergeX(xy2,xy,s,m,t); //合并两个已排序的子序列
}
}
int MergeX(X_Y xy2[],X_Y xy[],int s,int m,int t){
for(int a=s;a<=t;a++) {
xy[a]=xy2[a];
}
int i=s;
int j=m+1;
int k=s;
while(i<=m && j<=t) { //取较小的放入r1[k]
if(xy[i].x<=xy[j].x)
xy2[k++]=xy[i++];
else
xy2[k++]=xy[j++];
}
if(i<=m) { //若第一个子序列没处理完,则进行收尾处理
while(i<=m)
xy2[k++]=xy[i++];
}
else { //若第二个子序列没处理完,则进行收尾处理
while(j<=t)
xy2[k++]=xy[j++];
}
return 0;
}
///
找到中间数
///
void zhongjianshu() {
m=(xy[4].x+xy[5].x)/2;
for(int i=0;i<10;i++) {
if(xy[i].x<=m) {
mi=i;
}
}
}
//
//找到S1的最近距离
//
void min1() {
double x;
for(int i=0;i<=mi;i++) {
for(int j=i+1;j<=mi;j++) {
x=Math.sqrt((xy[i].x-xy[j].x)*(xy[i].x-xy[j].x)+(xy[i].y-xy[j].y)*(xy[i].y-xy[j].y));
if(x<min1) {
min1=x;
min1_i_1=i;
min1_i_2=j;
}
}
}
System.out.println("S1的最近距离为:"+min1);
}
//
//找到S2的最近距离
//
void min2() {
double x;
for(int i=mi+1;i<length;i++) {
for(int j=i+1;j<length;j++) {
x=Math.sqrt((xy[i].x-xy[j].x)*(xy[i].x-xy[j].x)+(xy[i].y-xy[j].y)*(xy[i].y-xy[j].y));
if(x<min2) {
min2=x;
min2_i_1=i;
min2_i_2=j;
}
}
}
System.out.println("S2的最近距离为:"+min2);
}
//
//找到S1和S2的最近距离
//
void compare() {
min=min1<min2?min1:min2;
System.out.println("S1和S2中最近距离为:"+min);
}
//
//找到距离中线范围的点(SS1)
//
void SS1() {
for(int i=0;i<length;i++) {
if(xy[i].x>=(m-min) && xy[i].x<=m) {
countSS1++;
}
}
SS1=new X_Y[countSS1];
int j=0;
for(int i=0;i<length;i++) {
if(xy[i].x>=(m-min) && xy[i].x<=m) {
SS1[j]=xy[i];
j++;
}
}
System.out.print("SS1的点为:");
for(int i=0;i<countSS1;i++) {
System.out.print("("+SS1[i].x+","+SS1[i].y+")"+" ");
}
System.out.println();
}
//
//找到距离中线范围的点(SS2)
//
void SS2() {
for(int i=0;i<length;i++) {
if(xy[i].x>m && xy[i].x<=m+min) {
countSS2++;
}
}
SS2=new X_Y[countSS2];
int j=0;
for(int i=0;i<length;i++) {
if(xy[i].x>m && xy[i].x<=(m+min)) {
SS2[j]=xy[i];
j++;
}
}
System.out.print("SS2的点为:");
for(int i=0;i<countSS2;i++) {
System.out.print("("+SS2[i].x+","+SS2[i].y+")"+" ");
}
System.out.println();
}
/
//对SS1按Y轴排序
/
void initSortSS1Y(){
SS1_2=new X_Y[countSS1];
MergeSortY(SS1,SS1_2,0,countSS1-1);
System.out.print("排序后的SS1为:");
for(int i=0;i<countSS1;i++) {
SS1[i]=SS1_2[i];
System.out.print("("+SS1[i].x+","+SS1[i].y+")"+" ");
}
System.out.println();
}
/
//对SS2按Y轴排序
/
void initSortSS2Y(){
SS2_2=new X_Y[countSS2];
MergeSortY(SS2,SS2_2,0,countSS2-1);
System.out.print("排序后的SS2为:");
for(int i=0;i<countSS2;i++) {
SS2[i]=SS2_2[i];
System.out.print("("+SS2[i].x+","+SS2[i].y+")"+" ");
}
System.out.println();
}
//
//
///
void MergeSortY(X_Y SS1[],X_Y SS1_2[],int s,int t){
int m;
if(s==t)
SS1_2[s]=SS1[s];
else {
m=(s+t)/2;
MergeSortY(SS1,SS1_2,s,m); //归并前半个子序列
MergeSortY(SS1,SS1_2,m+1,t); //归并后半个子序列
MergeY(SS1_2,SS1,s,m,t); //合并两个已排序的子序列
}
}
int MergeY(X_Y SS1_2[],X_Y SS1[],int s,int m,int t){
for(int a=s;a<=t;a++) {
SS1[a]=SS1_2[a];
}
int i=s;
int j=m+1;
int k=s;
while(i<=m && j<=t) { //取较小的放入r1[k]
if(SS1[i].y<=SS1[j].y)
SS1_2[k++]=SS1[i++];
else
SS1_2[k++]=SS1[j++];
}
if(i<=m) { //若第一个子序列没处理完,则进行收尾处理
while(i<=m)
SS1_2[k++]=SS1[i++];
}
else { //若第二个子序列没处理完,则进行收尾处理
while(j<=t)
SS1_2[k++]=SS1[j++];
}
return 0;
}
//
void min3() {
for(int i=0;i<countSS1;i++) {
for(int j=0;j<countSS2;j++) {
if(SS2[j].y>=(SS1[i].y-min) && SS2[j].y<=(SS1[i].y+min) ) {
min3=Math.sqrt((SS1[i].x-SS2[j].x)*(SS1[i].x-SS2[j].x)+(SS1[i].y-SS2[j].y)*(SS1[i].y-SS2[j].y));
min3_i_1=i;
min3_i_2=j;
}
}
}
System.out.println("第三个最近距离为:"+min3);
}
void Min() {
System.out.println("最近距离为"+min);
double min=999;
if(min1<min2) {
min=min1;
min_1=min1_i_1;
min_2=min1_i_2;
}
else {
min=min2;
min_1=min2_i_1;
min_2=min2_i_2;
}
if(min>min3) {
min=min3;
min_1=min3_i_1;
min_2=min3_i_2;
System.out.print("最近点为");
System.out.print("("+SS1[min3_i_1].x+","+SS1[min3_i_1].y+")"+" ");
System.out.print("("+SS2[min3_i_2].x+","+SS2[min3_i_2].y+")"+" ");
System.out.println();
}
else if(min==min1) {
System.out.print("最近点为");
System.out.print("("+xy[min1_i_1].x+","+xy[min1_i_1].y+")"+" ");
System.out.print("("+xy[min1_i_2].x+","+xy[min1_i_2].y+")"+" ");
System.out.println();
}
else {
System.out.print("最近点为");
System.out.print("("+xy[min2_i_1].x+","+xy[min2_i_1].y+")"+" ");
System.out.print("("+xy[min2_i_2].x+","+xy[min2_i_2].y+")"+" ");
System.out.println();
}
}
}