C++_最接近點對問題

  1. 問題描述、

問題描述:最接近點對問題,給定平面上n個點,找其中的一對點,使得在n個點組成的所有點對中,該點對間的距離最小。

  1. 設計思路

設計思路:設S中的點爲平面上的點,它們都有2個座標值x和y。爲了將平面上點集S線性分割爲大小大致相等的2個子集S1和S2,我們選取一垂直線l:x=m來作爲分割直線。其中m爲S中各點x座標的中位數。由此將S分割爲S1={p∈S|px≤m}和S2={p∈S|px>m}。從而使S1和S2分別位於直線l的左側和右側,且S=S1∪S2。由於m是S中各點x座標值的中位數,因此S1和S2中的點數大致相等。遞歸地在S1和S2上解最接近點對問題,我們分別得到S1和S2中的最小距離d1和d2。現設d=min(d1,d2)。若S的最接近點對(p,q)之間的距離d(p,q)<d則p和q必分屬於S1和S2。不妨設p∈S1,q∈S2。那麼p和q距直線l的距離均小於d。因此,我們若用P1和P2分別表示直線l的左邊和右邊的寬爲d的2個垂直長條,則p∈S1,q∈S2,如圖所示:

   距直線l的距離小於d的所有點

     在一維的情形,距分割點距離爲d的2個區間(m-d,m](m,m+d]中最多各有S中一個點。因而這2點成爲唯一的末檢查過的最接近點對候選者。二維的情形則要複雜些,此時,P1中所有點與P2中所有點構成的點對均爲最接近點對的候選者。在最壞情況下有n2/4對這樣的候選者。但是P1和P2中的點具有以下的稀疏性質,它使我們不必檢查所有這n^2/4對候選者。考慮P1中任意一點p,它若與P2中的點q構成最接近點對的候選者,則必有d(p,q)<d。滿足這個條件的P2中的點有多少個呢?容易看出這樣的點一定落在一個d×2d的矩形R中,如下圖所示:

包含點q的dX2d矩形R

    由d的意義可知P2中任何2個S中的點的距離都不小於d。由此可以推出矩形R中最多隻有6個S中的點。事實上,我們可以將矩形R的長爲2d的邊3等分,將它的長爲d的邊2等分,由此導出6個(d/2)×(2d/3)的矩形。如左圖所示:

矩陣R中點的稀疏性

    若矩形R中有多於6個S中的點,則由鴿舍原理易知至少有一個δ×2δ的小矩形中有2個以上S中的點。設u,v是這樣2個點,它們位於同一小矩形中,則:

因此d(u,v)≤5d/6<d 。這與d的意義相矛盾。也就是說矩形R中最多隻有6個S中的點。圖4(b)是矩形R中含有S中的6個點的極端情形。由於這種稀疏性質,對於P1中任一點p,P2中最多隻有6個點與它構成最接近點對的候選者。因此,在分治法的合併步驟中,我們最多只需要檢查6×n/2=3n對候選者,而不是n^2/4對候選者。這是否就意味着我們可以在O(n)時間內完成分治法的合併步驟呢?現在還不能作出這個結論,因爲我們只知道對於P1中每個S1中的點p最多只需要檢查P2中的6個點,但是我們並不確切地知道要檢查哪6個點。爲了解決這個問題,我們可以將p和P2中所有S2的點投影到垂直線l上。由於能與p點一起構成最接近點對候選者的S2中點一定在矩形R中,所以它們在直線l上的投影點距p在l上投影點的距離小於d。由上面的分析可知,這種投影點最多隻有6個。因此,若將P1和P2中所有S的點按其y座標排好序,則對P1中所有點p,對排好序的點列作一次掃描,就可以找出所有最接近點對的候選者,對P1中每一點最多隻要檢查P2中排好序的相繼6個點。

  1. 數據結構:

a[N]:存放隨機生成的點集

b[N],c[N]:分別存放分塊後的兩部分點集

t[1],q[2],p[2],o[2]:工作數組

d:兩點直接距離

dmin1:第一部分中最近兩點之間距離

dmin2:第二部分中最近兩點之間距離

dmin:最近兩點之間距離

  1. 算法描述:
  1. For i=0 to N
  2.   a[i].x<-rand()%101,a[i].y<-rand()%101//隨機生成N個空間座標點
  3. For i=0 to N
  4.   If(a[i].x<N/2) then
  5.     {b[j]=a[i];j++}
  6.   Else
  7.     {c[k]=a[i];k++}
  8. For i=0 to j
  9.   For r=i+1 to j
  10.     d=sqar((b[i].x-b[r].x)²+(b[i].y-b[r].y)²)
  11.     If(d<dmin1) then
  12.       {dmin1=d;p[0]=b[i];p[1]=b[r]}
  13.  For i=0 to k
  14.    For r=i+1 to k
  15.      d=sqar((c[i].x-c[r].x)²+(c[i].y-c[r].y)²)
  16.      If(d<dmin2) then
  17.       {dmin2=d;q[0]=c[i];q[1]=c[r]}
  18. dmin=min{dmin1,dmin2};o[2]=min{p[2],q[2]}
  19. for i=0 to j
  20.   if((c[r].x-N/2)<dmin) and (c[r].y-b[i].y)<dmin)  then
  21.     {d=d(c[r],b[i]);o[0]=b[1];o[1]=c[r]}
  22.   If(d<dmin)  then
  23.     dmin=d;
  24. Output(d,o[2])
  1. 測試用例:隨機輸入100個點爲:(41,85) (72,38) (80,69) (65,68) (96,22) (49,67) (51,61) (63,87) (66,24) (80,83) (71,60) (64,52) (90,60) (49,31) (23,99) (94,11) (25,24) (51,15) (13,39) (67,97) (19,76) (12,33) (99,18) (92,35) (74,0) (95,71) (39,33) (39,32) (37,45) (57,71) (95,5) (71,24) (86,8) (51,54) (74,24) (75,70) (33,63) (29,99) (58,94) (52,13) (35,99) (46,57) (71,23) (17,3) (94,48) (77,18) (83,11) (83,25) (59,62) (2,78) (86,7) (94,65) (80,32) (39,84) (60,65) (72,61) (58,84) (8,72) (12,19) (47,49) (49,59) (71,52) (34,22) (21,20) (92,33) (80,39) (74,9) (28,97) (100,93) (29,25) (4,66) (79,81) (98,21) (91,62) (82,4) (59,100) (34,1) (51,80) (92,69) (77,39) (38,97) (51,34) (35,19) (22,1) (67,9) (90,31) (82,11) (51,84) (78,70) (74,42) (100,88) (53,80) (57,62) (32,51) (48,63) (92,46) (4,61) (31,98) (69,52) (88,20)
  2. 運行得空間內最接近點對爲:

點:(71,24) 點:(71,23)

兩點之間距離爲 1

  1. 設計及測試過程

第一步:提出問題;

第二步:問題轉換;

第三步:算法構思;

第四步:僞碼描述;

第五步:代碼編寫;

第六步:代碼測試;

第七步:代碼修正;

#include <iostream>
using namespace std;
#define N 100
struct node
{
	float x;
	float y;
}a[N],b[N],c[N],t[1],q[2],p[2],o[2];
int main()
{
	int i,r,j=0,k=0;
	float d,dmin1=200,dmin2=200,dmin;
	for(i=0;i<N;i++)
	{
		a[i].x=rand()%101;
		a[i].y=rand()%101;
	}
	cout<<"隨機生成空間內100個點分別爲"<<endl;
	for(i=0;i<N;i++)
		cout<<"("<<a[i].x<<","<<a[i].y<<") ";
	for(i=0;i<N;i++)
	{
		if(a[i].x<50)
		{
			b[j]=a[i];
			j++;
		}
		else
		{
			c[k]=a[i];
			k++;
		}
	}
	for(i=0;i<j;i++)
	{
		for(r=i+1;r<j;r++)
		{
			d=sqrt((b[i].x-b[r].x)*(b[i].x-b[r].x)+(b[i].y-b[r].y)*(b[i].y-b[r].y));
			if(d<dmin1)
			{
				dmin1=d;
				p[0]=b[i];
				p[1]=b[r];
			}
		}
	}
	for(i=0;i<k;i++)
	{
		for(r=i+1;r<k;r++)
		{
			d=sqrt((c[i].x-c[r].x)*(c[i].x-c[r].x)+(c[i].y-c[r].y)*(c[i].y-c[r].y));
			if(d<dmin2)
			{
				dmin2=d;
				q[0]=c[i];
				q[1]=c[r];
			}
		}
	}
	if(dmin1<dmin2)
	{
		dmin=dmin1;
		o[0]=p[0];
		o[1]=p[1];
	}
	else
	{
		dmin=dmin2;
		o[0]=q[0];
		o[1]=q[1];
	}
	for(i=0;i<j;i++)
		if((b[i].x-50)*(b[i].x-50)<dmin*dmin)
		{
			for(r=0;r<k;r++)
			{
				if((c[r].x-50)*(c[r].x-50)<dmin*dmin&&(c[r].y-b[i].y)*(c[r].y-b[i].y)<dmin*dmin)
				{
					d=sqrt((b[i].x-c[r].x)*(b[i].x-c[r].x)+(b[i].y-c[r].y)*(b[i].y-c[r].y));
					if(d<dmin)
					{
						dmin=d;
						o[0]=b[i];
						o[1]=c[r];
					}
				}
			}
		}
	cout<<endl<<"空間內最接近點對爲"<<endl;
	for(i=0;i<2;i++)
		cout<<"點:("<<o[i].x<<","<<o[i].y<<") ";
	cout<<endl<<"兩點之間距離爲 ";
	cout<<dmin;
	system("pause");
	return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章