前言
提示:忙里偷闲,写点小算法,这次是介绍关于用暴力法解最近对问题和凸包问题。
提示:以下是本篇文章正文内容,下面案例可供参考
一、最近对问题
1.最近对问题
所谓最近对问题就是在包含n个点集中,找出距离最近的两个点。为了找出最近对,只需要分别计算每一对点之间的距离,然后找出距离最小的那一对即可。
2.最近对的伪代码
//使用蛮力法求平面中距离最近的两个点
//输入:一个n个点的集合
//输出:最近的两个点
d←∞
for i←1 to i←n-1 do
for j←i+1 to n do
d ←min(d,sqrt((xi-xj)²+(yi-yj)²)) //sqrt是开平方函数
3.C++实现
#include "iostream"
#include "time.h"
#include "stdlib.h"
#include "limits.h"// 导入最大值
#include "math.h"//调用pow函数
using namespace std;
void toFind(int a[10][2],int length)
{
int min=INT_MAX;//暂定为最大值
int flag_i=0;//记录两个最近的点
int flag_j=0;
for(int i=0;i<length;i++)
{
for(int j=i+1;j<length;j++)
{
int cal=pow((a[i][0]-a[j][0]),2)+pow((a[i][1]-a[j][1]),2);
if(min>cal)
{
min=cal;
flag_i=i;
flag_j=j;
}
}
}
cout<<"最近的一对点是"<<flag_i+1<<","<<flag_j+1<<",它们的距离是"<<pow(min,0.5)<<endl;
}
int main()
{
srand((unsigned)time(NULL));//种下随机数种子
int a[10][2];
for(int i=0;i<10;i++)
{
for(int j=0;j<2;j++)
{
a[i][j]=rand()%200;//生成200以内的坐标点
}
}
for(int i=0;i<10;i++)
{
cout<<"第"<<i+1<<"个点:";
for(int j=0;j<2;j++)
{
cout<<a[i][j];
if(j==0)
cout<<",";
}
cout<<endl;
}
int length=sizeof(a)/sizeof(a[0]);
toFind(a,length);
return 0;
}
4.运行结果截图
二、凸包问题
1.凸包问题
凸包问题就是在一个有n个点集的平面上,找出所有的“极点”,这些极点所构成的边界能够把其他所有的点都能包含在内。
2.解法思路
基于“边界包含所有的点”的思想,对于在n个点集中的两个点Pi和Pj,当且仅当该集合中的其他点都位于穿过这两点的直线的同一边时,它们的连线是该集合凸包边界的一部分。运用平面解析几何的知识:
坐标平面的两个点(x1,y1),(y1,y2)可满足直线方程:ax+by=c
于是可以得到:a=y2-y1,b=x1-x2,c=x1y2-y1x2。
所以程序的大致思路如下:
1.任意取两个点确定一种a,b,c三个参数。
2.将每一对点代入到所确定的a,b,c中,判定ax+by>c还是ax+by<c,如果所有的点都大于c或者都小于c,说明对应确定a,b,c所确定的一对点属于“极点”。
3.如此重复1,2,最终得到所有的极点。
程序流程图(伪)如下:
3.C++实现
#include "iostream"
#include "time.h"
#include "stdlib.h"
using namespace std;
int result[10][2];//保存最后的结果
int num=0;//统计极点数量
bool cal(int arry[10][2],int length,int a,int b,int c)//解析几何计算
{
bool flag1=false;
bool flag2=false;
for(int i=0;i<length;i++)
{
int cals=arry[i][0]*a+arry[i][1]*b;//计算不等式左边的值
if(cals>c)
flag1=true;// 1 0
else if(cals<c)
flag2=true;// 0 1
}
return flag1!=flag2;//一真一假说明所有的点在同一边
}
void toFind(int arry[10][2],int length)
{
int aa=0;//a,b,c三个参数
int b=0;
int c=0;
for(int i=0;i<length;i++)
{
for(int j=i+1;j<length;j++)
{
aa=arry[j][1]-arry[i][1];//a=y2-y1
b=arry[i][0]-arry[j][0];//b=x1-x2
c=arry[i][0]*arry[j][1]-arry[i][1]*arry[j][0];//c=x1y2-y1x2
bool bo=cal(arry,length,aa,b,c);
if(bo)//如果为真的话
{
if(num==0)//第一次将两个点都加入结果数组里面
{
result[num][0]=arry[i][0];
result[num][1]=arry[i][1];
num++;
result[num][0]=arry[j][0];
result[num][1]=arry[j][1];
num++;
}
else//不是第一次,则要检测是否有重复的点
{
bool flag1=true;
bool flag2=true;
for(int k=0;k<num;k++)
{
if(result[k][0]==arry[i][0]&&result[k][1]==arry[i][1])//检测第一个点是否重复
{
flag1=false;
}
if(result[k][0]==arry[j][0]&&result[k][1]==arry[j][1])//检测第二个点是否重复
{
flag2=false;
}
}
if(flag1==true)//第一个点不重复的话
{
result[num][0]=arry[i][0];
result[num][1]=arry[i][1];
num++;
}
if(flag2==true)//第二个点不重复的话
{
result[num][0]=arry[j][0];
result[num][1]=arry[j][1];
num++;
}
}
}
}
}
}
int main()
{
srand((unsigned)time(NULL));//种下随机数种子
int a[10][2];
for(int i=0;i<10;i++)
{
for(int j=0;j<2;j++)
{
a[i][j]=rand()%200;//生成200以内的坐标点
}
}
for(int i=0;i<10;i++)
{
cout<<"第"<<i+1<<"个点:";
for(int j=0;j<2;j++)
{
cout<<a[i][j];
if(j==0)
cout<<",";
}
cout<<endl;
}
int length=sizeof(a)/sizeof(a[0]);
toFind(a,length);
cout<<"构成凸包的极点坐标:"<<endl;
for(int i=0;i<num;i++)
{
cout<<i+1<<"."<<result[i][0]<<","<<result[i][1]<<endl;;
}
return 0;
}