分治法-最近點對問題


設p1=(x1,y1),p2=(x2,y2)...pn=(xn,yn)是平面n上n個點構成的集合S,最近對問你就是找出集合S中距離最近的點對。

分支策略:

    (1)划分:將集合S分成兩個子集S1和S2,根據平衡子問題原則,每個子集中大約有n/2個點,設集合S的最近點對是pi和pj(1<=i,j<=n)

                        則有以下三種情況 1.pi∈S1,pj∈S1

                                                       2.pi∈S1,pj∈S2

                                                       3.pi∈S2, pj∈S2

     (2)求解子問題:對於划分階段的情況1和2可遞歸求解

                                   通過直線x=M(中位數),將空間划為兩部分,x<M和x>M分別求出左右最近點對距離,d1,d2,另d=min(d1,d2)

                                   則,只需考慮3,即x-d和x+d的區域之間的最近點對,按照Y坐標對區域內點進行排序,如果一個點對的距離

                                    小於d,他們一定在d*(2*d)的區域內。

                                   

                                      對於算法 nearest_pair( S,left,right)

                                       1.預處理:對點集合S={(x1,y1),(x2,y2)......(xn,yn)}按照x坐標升序排列

                                        2.如果n=2,則返回連點之間距離

                                        3.m

                                           計算{(x1,y1),(x2,y2).....(xm,ym)}之間的最近距離

                                          計算{(xm,ym)(xm+1,ym+1)....(xn,yn)}之間的最近距離

                                         d=min(d1,d2)

                                        4.依次計算S[l...r]的最近點對(將集合按照y升序排列,考察y-s[m].y<d的點)

                                                l=min(i)| S[m]-S[i]<d

                                               r=max(i)| S[i]-S[m]<d

// 實驗四.cpp: 定義控制台應用程序的入口點。

//最近對問題
//2018.4.18

#include "stdafx.h"
#include<iostream>
#include<stdio.h>
#include<stdio.h>
#include<algorithm>
#include<math.h>
#include<windows.h>
using namespace std;

struct point {
	double x;
	double y;
}P[100];
double distance(point p1, point p2) {
	return sqrt((p1.x - p2.x)*(p1.x - p2.x) + (p1.y - p2.y)*(p1.y - p2.y));
}
bool cmp1(point p1, point p2) {
	return p1.x < p2.x;
}
bool cmp2(point p1, point p2) {
	return p1.y < p2.y;
}
//蠻力法
double get_min(int n)
{
	double min = sqrt((P[0].x - P[1].x)*(P[0].x - P[1].x) + (P[0].y - P[1].y)*(P[0].y - P[1].y));
	for (int i = 0; i < n; i++) {
		for (int j = i + 1; j < n; j++) {
			double t = sqrt((P[i].x - P[j].x)*(P[i].x - P[j].x) + (P[i].y - P[j].y)*(P[i].y - P[j].y));
			if (min>t)
				min = t;
		}
	}
	return min;
}

//分治法
double nearest_pair(point S[],int left,int right) {
	cout << left << " " << right << endl;
	if (right-left == 1) {
		return distance(S[right], S[left]);
	}
	if (right - left == 2) {
		double d1 = distance(S[right], S[left]);
		double d2 = distance(S[right], S[right + 1]);
		double d3 = distance(S[right + 1], S[left]);
		d2 = min(d1, d2);
		d3 = min(d2, d3);
		return d3;
	}
	int m = (right+left) / 2;
	double d1 = nearest_pair(S,left, m);
	double d2 = nearest_pair(S, m+1,right);
	//sort(S+right, S+left, cmp2);
	double d = min(d1, d2);
	int l = left, r = right;
	while (S[l].x < S[m].x - d && l <= right);
		l++;
	while (S[r].x > S[m].x + d && r>=left)
		r++;
	sort(S + 1, S + r + 1, cmp2);
	double d3;
	for (int i = l; i <= r; i++) {
		for (int j = i + 1; j <= r; j++) {
			if (S[j].y - S[i].y >= d) {
				break;
			}
			else {
				d3 = distance(S[i], S[j]);
				if (d3 < d)
					d = d3;
			}
		}
	}
	return d;
}
int main()
{
	int n;
	cout << "Input n:";
	cin >> n;
	for (int i = 1; i <= n; i++) {
		cout << "Input the " << i << "th number:";
		cin >> P[i].x >> P[i].y;
	}
	sort(P + 1, P + n+1, cmp1);
	for (int i = 1; i <= n; i++) {
		cout << P[i].x << " " << P[i].y << endl;
	}
	double m = get_min(n);
	cout << m << endl;
	double m2 = nearest_pair(P, 1, n);
	cout << m2 << endl;
	system("pause");
	return 0;
}

  

                        

 

         

 

  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM