分治法求解平面n點中距離最近的兩點
阿新 • • 發佈:2019-01-28
步驟4:將L-d~L+d內的點以y值排序,對於每一個點(x1,y1)找出y值在y1-d~y1+d內的所有點,計算距離為d'。 如果d'小於d,令d=d',最後的d值就是答案。
實驗1 遞迴與分治演算法
一,實驗目的和要求
(1)進一步掌握遞迴演算法的設計思想以及遞迴程式的除錯技術;
(2)理解這樣一個觀點:分治與遞迴經常同時應用在演算法設計之中。
(3)分別用蠻力法和分治法求解最近對問題;
(4)分析演算法的時間效能,設計實驗程式驗證分析結論。
二,實驗內容
設p1=(x1, y1), p2=(x2, y2), …, pn=(xn, yn)是平面上n個點構成的集合S,設計演算法找出集合S中距離最近的點對。
三,實驗環境
Turbo C 或VC++
四,實驗學時
2學時,必做實驗
五,資料結構與演算法
#include<iostream.h>
#include<cmath>
#define TRUE 1
#define FALSE 0
typedef struct Node
{
double x;
double y;
}Node; //座標
typedef struct List
{
Node* data; //點
int count; //點的個數
}List;
typedef struct CloseNode
{
Node a;
Node b; //計算距離的兩個點
double space; //距離平方
}CloseNode;
int n; //點的數目
//輸入各點到List中
void create(List &L)
{
cout<<"請輸入平面上點的數目:\n";
cin>>n;
L.count=n;
L.data = new Node[L.count]; //動態空間分配
cout<<"輸入各點座標 :x_y):"<<endl;
for(int i=0;i<L.count;++i)
cin>>L.data[i].x>>L.data[i].y;
}
//求距離的平方
double square(Node a,Node b)
{
return ((a.x-b.x)*(a.x-b.x))+((a.y-b.y)*(a.y-b.y));
}
//蠻力法
void BruteForce(const List &L,CloseNode &cnode,int begin,int end)
{
for(int i=begin;i<=end;++i)
{
for(int j=i+1;j<=end;++j)
{
double space=square(L.data[i],L.data[j]);
if(space<cnode.space)
{
cnode.a=L.data[i];
cnode.b=L.data[j];
cnode.space=space;
}
}
}
}
//氣泡排序
void BubbleSort(Node r[],int length)
{
int change,n;
n=length;change=TRUE;
double b,c;
for(int i=0;i<n-1&&change;++i)
{
change=FALSE;
for(int j=0;j<n-i-1;++j)
{
if(r[j].x>r[j+1].x)
{
b=r[j].x;c=r[j].y;
r[j].x=r[j+1].x;r[j].y=r[j+1].y;
r[j+1].x=b;r[j+1].y=c;
change=TRUE;
}
}
}
}
//分治法中先將座標按X軸從小到大的順序排列
void paixu(List L)
{
BubbleSort(L.data,L.count); //呼叫氣泡排序
}
//左右各距中線d的區域的最近對演算法
void middle(const List & L,CloseNode &cnode,int mid,double midX)
{
int i,j; //分別表示中線左邊,右邊的點
double d=sqrt(cnode.space);
i=mid;
while(i>=0&&L.data[i].x>=(midX-d)) //在左邊的d區域內
{
j=mid;
while(L.data[++j].x<=(midX+d)&&j<=L.count) //在右邊的d區域內
{
if(L.data[j].y<(L.data[i].y-d)||L.data[j].y>(L.data[i].y+d)) //判斷縱座標是否在左邊某固定點的2d區域內
continue;
double space = square(L.data[i],L.data[j]);
if(cnode.space>space) //在滿足條件的區域內依次判斷
{
cnode.a=L.data[i];
cnode.b=L.data[j];
cnode.space=space;
}
}
--i;
}
}
//分治法求最近對
void DivideConquer(const List &L,CloseNode &closenode,int begin,int end)
{
if(begin!=end)
{
int mid = (begin+end)/2; //排列後的中間的那個點
double midX = L.data[mid].x;
DivideConquer(L,closenode,begin,mid); //繼續在左半邊用分治法求最近對
DivideConquer(L,closenode,mid+1,end); //繼續在右半邊用分治法求最近對
middle(L,closenode,mid,midX); //判斷左右各距中線d的區域,是否有最近對
}
}
void main()
{
//初始化
List list;
CloseNode closenode;
closenode.square=10000;//必須付初值,根據實際情況而定
closenode.space = 10000; //最近點的距離
create(list); //輸入各點到NList中
cout<<"各點座標為:"<<endl;
for(int i=0;i<list.count;++i)
cout<<"X="<<list.data[i].x<<" Y="<<list.data[i].y<<"\n";
BruteForce(list,closenode,0,list.count-1);
cout<<"用蠻力法求最近對:"<<endl;
cout<<"最近對為點 ("<<closenode.a.x<<","<<closenode.a.y<<")和點("<<closenode.b.x<<","<<closenode.b.y<<")\n"<<"最近距離為: "<<sqrt(closenode.space)<<endl;
cout<<endl<<endl;
cout<<"用分治法求最近對:"<<endl;
paixu(list);
cout<<"經過排序後的各點:"<<endl;
for(int j=0;j<list.count;++j)
cout<<"X="<<list.data[j].x<<" Y="<<list.data[j].y<<"\n";
DivideConquer(list,closenode,0,list.count-1);
cout<<"最近對為點 ("<<closenode.a.x<<","<<closenode.a.y<<")和點("<<closenode.b.x<<","<<closenode.b.y<<")\n"<<"最近距離為: "<<sqrt(closenode.space)<<endl;
}
實驗1 遞迴與分治演算法
一,實驗目的和要求
(1)進一步掌握遞迴演算法的設計思想以及遞迴程式的除錯技術;
(2)理解這樣一個觀點:分治與遞迴經常同時應用在演算法設計之中。
(3)分別用蠻力法和分治法求解最近對問題;
(4)分析演算法的時間效能,設計實驗程式驗證分析結論。
二,實驗內容
設p1=(x1, y1), p2=(x2, y2), …, pn=(xn, yn)是平面上n個點構成的集合S,設計演算法找出集合S中距離最近的點對。
三,實驗環境
Turbo C 或VC++
四,實驗學時
2學時,必做實驗
五,資料結構與演算法
#include<iostream.h>
#include<cmath>
#define TRUE 1
#define FALSE 0
typedef struct Node
{
double x;
double y;
}Node; //座標
typedef struct List
{
Node* data; //點
int count; //點的個數
}List;
typedef struct CloseNode
{
Node a;
Node b; //計算距離的兩個點
double space; //距離平方
}CloseNode;
int n; //點的數目
//輸入各點到List中
void create(List &L)
{
cout<<"請輸入平面上點的數目:\n";
cin>>n;
L.count=n;
L.data = new Node[L.count]; //動態空間分配
cout<<"輸入各點座標 :x_y):"<<endl;
for(int i=0;i<L.count;++i)
cin>>L.data[i].x>>L.data[i].y;
}
//求距離的平方
double square(Node a,Node b)
{
return ((a.x-b.x)*(a.x-b.x))+((a.y-b.y)*(a.y-b.y));
}
//蠻力法
void BruteForce(const List &L,CloseNode &cnode,int begin,int end)
{
for(int i=begin;i<=end;++i)
{
for(int j=i+1;j<=end;++j)
{
double space=square(L.data[i],L.data[j]);
if(space<cnode.space)
{
cnode.a=L.data[i];
cnode.b=L.data[j];
cnode.space=space;
}
}
}
}
//氣泡排序
void BubbleSort(Node r[],int length)
{
int change,n;
n=length;change=TRUE;
double b,c;
for(int i=0;i<n-1&&change;++i)
{
change=FALSE;
for(int j=0;j<n-i-1;++j)
{
if(r[j].x>r[j+1].x)
{
b=r[j].x;c=r[j].y;
r[j].x=r[j+1].x;r[j].y=r[j+1].y;
r[j+1].x=b;r[j+1].y=c;
change=TRUE;
}
}
}
}
//分治法中先將座標按X軸從小到大的順序排列
void paixu(List L)
{
BubbleSort(L.data,L.count); //呼叫氣泡排序
}
//左右各距中線d的區域的最近對演算法
void middle(const List & L,CloseNode &cnode,int mid,double midX)
{
int i,j; //分別表示中線左邊,右邊的點
double d=sqrt(cnode.space);
i=mid;
while(i>=0&&L.data[i].x>=(midX-d)) //在左邊的d區域內
{
j=mid;
while(L.data[++j].x<=(midX+d)&&j<=L.count) //在右邊的d區域內
{
if(L.data[j].y<(L.data[i].y-d)||L.data[j].y>(L.data[i].y+d)) //判斷縱座標是否在左邊某固定點的2d區域內
continue;
double space = square(L.data[i],L.data[j]);
if(cnode.space>space) //在滿足條件的區域內依次判斷
{
cnode.a=L.data[i];
cnode.b=L.data[j];
cnode.space=space;
}
}
--i;
}
}
//分治法求最近對
void DivideConquer(const List &L,CloseNode &closenode,int begin,int end)
{
if(begin!=end)
{
int mid = (begin+end)/2; //排列後的中間的那個點
double midX = L.data[mid].x;
DivideConquer(L,closenode,begin,mid); //繼續在左半邊用分治法求最近對
DivideConquer(L,closenode,mid+1,end); //繼續在右半邊用分治法求最近對
middle(L,closenode,mid,midX); //判斷左右各距中線d的區域,是否有最近對
}
}
void main()
{
//初始化
List list;
CloseNode closenode;
closenode.square=10000;//必須付初值,根據實際情況而定
closenode.space = 10000; //最近點的距離
create(list); //輸入各點到NList中
cout<<"各點座標為:"<<endl;
for(int i=0;i<list.count;++i)
cout<<"X="<<list.data[i].x<<" Y="<<list.data[i].y<<"\n";
BruteForce(list,closenode,0,list.count-1);
cout<<"用蠻力法求最近對:"<<endl;
cout<<"最近對為點 ("<<closenode.a.x<<","<<closenode.a.y<<")和點("<<closenode.b.x<<","<<closenode.b.y<<")\n"<<"最近距離為: "<<sqrt(closenode.space)<<endl;
cout<<endl<<endl;
cout<<"用分治法求最近對:"<<endl;
paixu(list);
cout<<"經過排序後的各點:"<<endl;
for(int j=0;j<list.count;++j)
cout<<"X="<<list.data[j].x<<" Y="<<list.data[j].y<<"\n";
DivideConquer(list,closenode,0,list.count-1);
cout<<"最近對為點 ("<<closenode.a.x<<","<<closenode.a.y<<")和點("<<closenode.b.x<<","<<closenode.b.y<<")\n"<<"最近距離為: "<<sqrt(closenode.space)<<endl;
}