算法实验一
【实验内容】利用分治算法、蛮力法,编程实现最近点对问题,并进行时间复杂性分析。注:要求针对计算机随机生成的100点对数据,分别用蛮力法和分治法求解最近点对,对比其复杂性。
【编译环境】devc++ 5.11
【解题思路】
1.随机生成100对实数点对数据
2.用蛮力法求解最近点对问题
3.用分治法求解最近点对问题
4.对于复杂性
【参考内容】
【代码分析】
1.随机生成100对实数点对数据
每个点的表示
要求使用一个结构体表示每个点在xy轴上的坐标和该点的唯一标识id
(命名有些不规范,正在学习…)
typedef struct Point
{
double x;
double y;
int id;
}point;
利用c++库函数生成
#include<fstream>
#include<iostream>
#include<ctime>
#include<random>
#define MAX 100 //点对数
#define MAXXY 100 //点对最大值
void randomint(point* num)//生成100组随机数
{
default_random_engine random(time(0));//利用当前时间产生随机数种子
uniform_real_distribution<double> randnum(0-MAXXY, MAXXY);//产生随机数的上限MAXXY,下限0-MAXXY,类型为double
ofstream outFile;//文件操作用来保存生成的随机数
outFile.open("sample.txt"); //打开文件
outFile<<"当前MAX值为: "<<MAX<<endl;
outFile<<"当前MAXXY值为: "<<MAXXY<<endl;
for(int i=0;i<MAX;i++)
{
num[i].x = randnum(random);//每次调用都产生一次随机数
num[i].y = randnum(random);
num[i].id = i;
outFile<<num[i].id <<" "<<num[i].x <<" "<<num[i].y <<endl;//输入当前目录下的sample。txt文件内保存案例
}
}
2.蛮力法
#include<algorithm>
void enumerate(point* num)//第一种方法枚举方法
{
//依次计算两个点之间距离记录最小值
double mindis = MAXXY*MAXXY*2+1;//确保mindis初始值是最大的
int minpoint0;
int minpoint1;
if(MAX == 2)//只有两个点的时候直接输出结果
{
minpoint0 = 0;
minpoint1 = 1;
double x = num[0].x>num[1].x?num[0].x-num[1].x:num[1].x-num[0].x;
double y = num[0].y>num[1].y?num[0].y-num[1].y:num[1].y-num[0].y;
mindis = x*x+y*y;
}
else
for(int i=0;i<MAX-1;i++)
for(int j=i+1;j<MAX;j++)
{
double x = num[i].x>num[j].x?num[i].x-num[j].x:num[j].x-num[i].x;
double y = num[i].y>num[j].y?num[i].y-num[j].y:num[j].y-num[i].y;
if(x*x+y*y<mindis)
{
mindis = x*x+y*y;
minpoint0 = i;
minpoint1 = j;
}
}
mindis = sqrt(mindis);
cout<< mindis<<endl;
cout<< num[minpoint0].id<<" "<<num[minpoint1].id<<endl;
cout<< num[minpoint0].x<<" "<<num[minpoint0].y <<endl;
cout<< num[minpoint1].x<<" "<<num[minpoint1].y <<endl;
}
3.分治法
所需结构
typedef struct distance//分治法递归函数返回的结构体
{
double dis;
point point1;
point point2;
}dist;
一些单独功能的函数
bool sortcmpx(point num1,point num2)//x坐标排序函数所需比较函数
{
if(num1.x >num2.x )
return 0;
else
return 1;
}
bool sortcmpy(point num1,point num2)//y坐标排序函数所需比较函数
{
if(num1.y >num2.y )
return 0;
else
return 1;
}
double getdis(point num1, point num2)//返回两个point点的距离
{
double disx = num1.x >num2.x ?num1.x -num2.x:num2.x-num1.x ;
double disy = num1.y >num2.y ?num1.y -num2.y:num2.y-num1.y ;
return disx*disx+disy*disy;
}
分治法主要代码
dist* divide(point* num,int length)//分治法divide
{
dist* dis = new dist;
dist* dis1 = new dist;
dist* dis2 = new dist;
dist* dis3 = new dist;
//图片第一步:递归到长度为2时最短距离即为两者的距离
if(length ==2)
{
dis->dis = getdis(num[0],num[1]);
dis->point1 = num[0];
dis->point2 = num[1];
free(dis1);
free(dis2);
free(dis3);
return dis;
}
dis3->dis = MAXXY*MAXXY*2;//初始化最大
//图片第二步
int mid = length/2;
sort(num,num+length,sortcmpx);
//coutx用来显示排序后的结果,方便调试
//coutx(num,length);
//图片第三步
dis1 = divide(num,mid+1);//mid+1确保前一部分最少有两个,不会出现一个的情况
//图片第四步
dis2 = divide(num+mid,length-mid);
//图片第五步
if(dis1->dis >dis2->dis )
{
dis->dis = dis2->dis ;
dis->point1 = dis2->point1 ;
dis->point2 = dis2->point2 ;
}
else
{
dis->dis = dis1->dis ;
dis->point1 = dis1->point1 ;
dis->point2 = dis1->point2 ;
}
//求解最短距离在中间的情况
point p1[MAX];
point p2[MAX];
int p1num=0;
int p2num=0;
//取距离mid点的x坐标距离不大于dis的点
//图片第六步
for(int i=0;i<length;i++)
{
if(num[i].x <=num[mid].x && num[i].x >=num[mid].x -dis->dis )
{
p1[p1num].x = num[i].x ;
p1[p1num].y = num[i].y ;
p1[p1num].id = num[i].id ;
p1num++;
}
else if(num[i].x >num[mid].x && num[i].x <=num[mid].x +dis->dis )
{
p2[p2num].x = num[i].x ;
p2[p2num].y = num[i].y ;
p2[p2num].id = num[i].id ;
p2num++;
}
}
//按照y坐标升序排序
//图片第七步
sort(p1,p1+p1num,sortcmpy);
sort(p2,p2+p2num,sortcmpy);
//图片第八步
//分开计算p1和p2。p1中的点每个点最多取5个,p2中的点每个点最多取6个
//计算p1中的每个点的最短距离情况
for(int i=0;i<p1num;i++)
{
int count = 0;//已经取得点的个数
for(int j=0;j<p2num;j++)
{
if(count>4)
break;
if(p2[j].y >=p1[i].y && p2[j].y<=p1[i].y +dis->dis )
{
count++;
double a = getdis(p1[i],p2[j]);
if(dis3->dis >a)
{
dis3->dis = a;
dis3->point1 = p1[i];
dis3->point2 = p2[j];
}
}
}
}
//计算p2中的每个点的最短距离情况
for(int i=0;i<p2num;i++)
{
int count = 0;//已经取得点的个数
for(int j=0;j<p1num;j++)
{
if(count>5)
break;
if(p1[j].y >=p1[i].y && p1[j].y<=p1[i].y +dis->dis )
{
count++;
double a = getdis(p2[i],p1[j]);
if(dis3->dis >a)
{
dis3->dis = a;
dis3->point1 = p2[i];
dis3->point2 = p1[j];
}
}
}
}
if(dis->dis >dis3->dis )
{
dis->dis = dis3->dis ;
dis->point1 =dis3->point1 ;
dis->point2 = dis3->point2 ;
}
//释放内存
free(dis1);
free(dis2);
free(dis3);
//图片第九步
return dis;
}
4.复杂性
蛮力法时间复杂度
分治法时间复杂度
5.实验结果
输出
前者蛮力法,后者分治法
相应目录下记录的案例
6.编译器报错可能原因
报错图片
解决方法
工具->编译选项:增加下列设置
7.源代码
#include<iostream>
#include<ctime>
#include<random>
#include<algorithm>
#include<fstream>
#define MAX 100
#define MAXXY 100
using namespace std;
typedef struct Point
{
double x;
double y;
int id;
}point;
void randomint(point* num)
{
default_random_engine random(time(0));
uniform_real_distribution<double> randnum(0-MAXXY, MAXXY);
ofstream outFile;
outFile.open("sample.txt");
outFile<<"当前MAX值为: "<<MAX<<endl;
outFile<<"当前MAXXY值为: "<<MAXXY<<endl;
for(int i=0;i<MAX;i++)
{
num[i].x = randnum(random);
num[i].y = randnum(random);
num[i].id = i;
outFile<<num[i].id <<" "<<num[i].x <<" "<<num[i].y <<endl;
}
}
void writedown(point* num)
{
for(int i =0;i<MAX;i++)
{
cout<<num[i].x <<" "<<num[i].y <<endl;
}
}
void enumerate(point* num)
{
double mindis = MAXXY*MAXXY*2+1;
int minpoint0;
int minpoint1;
if(MAX == 2)
{
minpoint0 = 0;
minpoint1 = 1;
double x = num[0].x>num[1].x?num[0].x-num[1].x:num[1].x-num[0].x;
double y = num[0].y>num[1].y?num[0].y-num[1].y:num[1].y-num[0].y;
mindis = x*x+y*y;
}
else
for(int i=0;i<MAX-1;i++)
for(int j=i+1;j<MAX;j++)
{
double x = num[i].x>num[j].x?num[i].x-num[j].x:num[j].x-num[i].x;
double y = num[i].y>num[j].y?num[i].y-num[j].y:num[j].y-num[i].y;
if(x*x+y*y<mindis)
{
mindis = x*x+y*y;
minpoint0 = i;
minpoint1 = j;
}
}
mindis = sqrt(mindis);
cout<< mindis<<endl;
cout<< num[minpoint0].id<<" "<<num[minpoint1].id<<endl;
cout<< num[minpoint0].x<<" "<<num[minpoint0].y <<endl;
cout<< num[minpoint1].x<<" "<<num[minpoint1].y <<endl;
}
bool sortcmpx(point num1,point num2)
{
if(num1.x >num2.x )
return 0;
else
return 1;
}
bool sortcmpy(point num1,point num2)
{
if(num1.y >num2.y )
return 0;
else
return 1;
}
void coutx(point *num,int length)
{
for(int i=0;i<length;i++)
{
cout<<num[i].x<<endl;
}
cout<<endl;
}
double getdis(point num1, point num2)
{
double disx = num1.x >num2.x ?num1.x -num2.x:num2.x-num1.x ;
double disy = num1.y >num2.y ?num1.y -num2.y:num2.y-num1.y ;
return disx*disx+disy*disy;
}
typedef struct distance
{
double dis;
point point1;
point point2;
}dist;
dist* divide(point* num,int length)
{
dist* dis = new dist;
dist* dis1 = new dist;
dist* dis2 = new dist;
dist* dis3 = new dist;
if(length ==2)
{
dis->dis = getdis(num[0],num[1]);
dis->point1 = num[0];
dis->point2 = num[1];
free(dis1);
free(dis2);
free(dis3);
return dis;
}
dis3->dis = MAXXY*MAXXY*2;
int mid = length/2;
sort(num,num+length,sortcmpx);
//coutx(num,length);
dis1 = divide(num,mid+1);
dis2 = divide(num+mid,length-mid);
if(dis1->dis >dis2->dis )
{
dis->dis = dis2->dis ;
dis->point1 = dis2->point1 ;
dis->point2 = dis2->point2 ;
}
else
{
dis->dis = dis1->dis ;
dis->point1 = dis1->point1 ;
dis->point2 = dis1->point2 ;
}
point p1[MAX];
point p2[MAX];
int p1num=0;
int p2num=0;
for(int i=0;i<length;i++)
{
if(num[i].x <=num[mid].x && num[i].x >=num[mid].x -dis->dis )
{
p1[p1num].x = num[i].x ;
p1[p1num].y = num[i].y ;
p1[p1num].id = num[i].id ;
p1num++;
}
else if(num[i].x >num[mid].x && num[i].x <=num[mid].x +dis->dis )
{
p2[p2num].x = num[i].x ;
p2[p2num].y = num[i].y ;
p2[p2num].id = num[i].id ;
p2num++;
}
}
sort(p1,p1+p1num,sortcmpy);
sort(p2,p2+p2num,sortcmpy);
for(int i=0;i<p1num;i++)
{
int count = 0;
for(int j=0;j<p2num;j++)
{
if(count>4)
break;
if(p2[j].y >=p1[i].y && p2[j].y<=p1[i].y +dis->dis )
{
count++;
double a = getdis(p1[i],p2[j]);
if(dis3->dis >a)
{
dis3->dis = a;
dis3->point1 = p1[i];
dis3->point2 = p2[j];
}
}
}
}
for(int i=0;i<p2num;i++)
{
int count = 0;
for(int j=0;j<p1num;j++)
{
if(count>5)
break;
if(p1[j].y >=p1[i].y && p1[j].y<=p1[i].y +dis->dis )
{
count++;
double a = getdis(p2[i],p1[j]);
if(dis3->dis >a)
{
dis3->dis = a;
dis3->point1 = p2[i];
dis3->point2 = p1[j];
}
}
}
}
if(dis->dis >dis3->dis )
{
dis->dis = dis3->dis ;
dis->point1 =dis3->point1 ;
dis->point2 = dis3->point2 ;
}
free(dis1);
free(dis2);
free(dis3);
return dis;
}
void coutdivide(point* pointxy,int max)
{
dist* dis = divide(pointxy,max);
cout<<sqrt(dis->dis) <<endl;
cout<<dis->point1.id <<" "<<dis->point2.id <<endl;
cout<<dis->point1.x <<" "<<dis->point1.y <<endl;
cout<<dis->point2.x <<" "<<dis->point2.y <<endl;
}
int main()
{
point pointxy[MAX];
randomint(pointxy);
//writedown(pointxy);
enumerate(pointxy);
cout<<"-----分----------割----------符-----"<<endl;
coutdivide(pointxy,MAX);
}