演算法設計--蠻力法&&分治法求最近對問題(C++實現)
阿新 • • 發佈:2019-01-06
最近對問題?
設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; }