1. 程式人生 > >演算法設計--蠻力法&&分治法求最近對問題(C++實現)

演算法設計--蠻力法&&分治法求最近對問題(C++實現)

最近對問題?

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

兩種演算法思想:

1. 蠻力法:顧名思義,利用正常的思維,使用強硬的方式求解出結果。

2. 分治法:分治,分而治之,把大問題分解為小問題,主要有三個過程:劃分、求解子問題、合併。

直接上程式碼:

蠻力法求解最近對問題:

#include "iostream" 
#include "math.h" 
#include "time.h"
#include "stdlib.h" 
using namespace std; 
struct P 
{  
	int x;  
	int y; 
}; 
double ClosePoints(int n,P a[],int &index1,int &index2) 
{     
	double  d;     
	double  Dist=10000;  
	for (int i=0;i<n-1;i++)  
	{   
		for (int j=i+1;j<=n-1;j++)   
		{    
			d=(a[i].x-a[j].x)*(a[i].x-a[j].x)+(a[i].y-a[j].y)*(a[i].y-a[j].y);    
			if(d<=Dist)    
			{     
				Dist=d;     
				index1=i;     
				index2=j;    
			}   
		}  
	}  return Dist;   
} 
void main (void) 
{     
	clock_t start,end;  
	int g;  
	int s,e;  
	P a[10000];  
	for (int i=1;i<4;i++)  
	{    
		cout<<"輸入座標的個數(10000以內)";  
		cin>>g; 
		srand(time(NULL));   
		for (int r=0;r<g;r++)   
		{    
			a[r].x=rand()%(g-123);             
			a[r].y=rand()%(g-1234);   
		}   
		start=clock();   
		double w=ClosePoints(g,a,s,e);         
		end=clock();   
		cout<<"最近的兩個點是:P1("<<a[s].x<<","<<a[s].y<<") P2("<<a[e].x<<","<<a[e].y<<")"<<endl;   cout<<"距離是:"<<sqrt(w)<<endl;         
		cout<<"蠻力法求最近對用時:"<<(double)(end-start)/CLOCKS_PER_SEC<<"ms"<<endl;   
		cout<<"============================================================="<<endl;     
	}  
} 

分治法求解最近對問題:
#include<iostream>
#include "cstdio" 
#include "cstring" 
#include "math.h" 
#include "time.h" 
#include "stdlib.h" 
#include "algorithm"
using namespace std;
#define eps 1e-8
#define N 10000
//定義一個儲存座標的結構體
struct point	
{
	double x,y;
};

point node[N * 2];
point d[N];
point c[N];
point b[N];
int cmp(point a, point b)		//比較兩點之間的y值
{
	return a.y < b.y;
}
int cmp1(point a, point b)
{
	if(a.x != b.x)
		return a.x < b.x;
	return a.y < b.y;
}
double min(double a, double b)	//求a和b兩者較小值
{	
	return a > b? b:a;
}

double dx(double x1, double x2)	
{
	if((x1 - x2) > eps && (x1 - x2) < eps)
	{
		return 0;
	}
	else if(x1 > x2)
	{
		return x1 - x2;
	}
	else if(x1 < x2)
	{
		return x2 - x1;
	}
}

double ds(point a, point b)		//求兩點之間的距離
{
	return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
}
/**
* 最近對問題
* 三種情況:
* 1.在子集S1中
* 2.在自己S2中
* 3.最近的兩個點分別在子集S1和S2中
*/
double closestPoints(point node[], int n)
{
	int i, j;
	int Dist = 99999;		//無窮大數
	if(n < 2)				//只有一個點,不存在最近對
		return 0;
	int m = (n - 1) / 2;	//m是各個座標的中位數
	for(i = m + 1; i < n; i++)
	{
		b[i].x = node[i].x;
		b[i].y = node[i].y;
	}
	//劃分為兩個子問題,遞迴求解子問題
	double d1 = closestPoints(node, m + 1);		//得到S1中的最近距離d1
	double d2 = closestPoints(b, n - m - 1);	//得到S2中的最近距離d2
	double dm = min(d1, d2);					//求得d1與d2兩者之間較小值					
	int f,p;		//記錄點的個數
	p = 0;
	for(i = 0; i <= m; i++)				//找出S1中與x=m的距離小於dm的所有點,儲存在結構體c當中
	{
		if(dx(node[i].x,node[m].x) < dm)
		{
			c[p].x = node[i].x;
			c[p].y = node[i].y;
			p++;
		}
	}
	f=0;
	for(i = m + 1; i < n; i++)			//找出S2中與x=m的距離小於dm的所有點,儲存在結構題d當中
	{
		if(dx(node[i].x, node[m].x) < dm)
		{
			d[f].x = node[i].x;
			d[f].y = node[i].y;
			f++;
		}
	}

	sort(c, c+p,cmp);	//按照y軸的座標值升序排列
	sort(d, d+f,cmp);
	double ret = Dist;
	for(i = 0; i < p; i++)		//遍歷比較分別在S1和S2中兩點之間的距離
	{
		for(j = 0; j < f; j++)
		{
			double ans = ds(c[i], d[j]);
			ret = min(ret, ans);		//得出最近對距離
		}
	}
	return min(ret, dm);		//返回第三種情形與前兩種情形較小值
}
int main(void) 
{  
	int n,i;  
	for(int w=0;w<6;w++)  
	{   
		cout<<"輸入座標的數目:"<<endl;   
		cin>>n;   
		srand((unsigned)time(NULL));   
		for(i=0;i<n;i++)   
		{    
			node[i].x=rand()/(double)(RAND_MAX/10000);    
			node[i].y=rand()/(double)(RAND_MAX/10000);   
		}   
		sort(node,node+n,cmp);   
		clock_t start,end;   
		start=clock();
		closestPoints(node,n);               //系統呼叫十次分治法函式。   
		closestPoints(node,n);   
		closestPoints(node,n);   
		closestPoints(node,n);   
		closestPoints(node,n);   
		closestPoints(node,n);   
		closestPoints(node,n);   
		closestPoints(node,n);   
		closestPoints(node,n);   
		closestPoints(node,n);   
		end=clock();   
		cout<<"分治法求最近對用時為"<<double(end-start)/CLOCKS_PER_SEC<<"ms"<<endl;   
		cout<<"==========================================================="<<endl;  

	}
	system("pause");
	return 0;
}