暴力法解决最近对问题和凸包问题


前言

提示:忙里偷闲,写点小算法,这次是介绍关于用暴力法解最近对问题和凸包问题。


提示:以下是本篇文章正文内容,下面案例可供参考

一、最近对问题

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;
} 

4.运行截图

在这里插入图片描述

  • 3
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
凸包问题是指给定平面上的一组点,求出能包含所有这些点的最小凸多边形的问题蛮力是一种朴素的解,其基本思想是枚举所有可能的凸多边形并判断是否符合要求,最终得到最小凸多边形。 下面是一个用蛮力解决凸包问题的C语言代码示例: ```c #include <stdio.h> #include <stdlib.h> typedef struct{ int x; int y; } Point; int ccw(Point a, Point b, Point c){ int area = (b.x-a.x)*(c.y-a.y) - (c.x-a.x)*(b.y-a.y); if(area > 0) return 1; // 逆时针 else if(area < 0) return -1; // 顺时针 else return 0; // 平行 } int cmp(const void* p1, const void* p2){ Point* a = (Point*)p1; Point* b = (Point*)p2; if(a->x != b->x) return a->x - b->x; else return a->y - b->y; } void convex_hull(Point* points, int n){ qsort(points, n, sizeof(Point), cmp); Point* hull = (Point*)malloc(sizeof(Point) * n); int idx = 0, start = 0; for(int i=0; i<n; i++){ while(idx-start >= 2 && ccw(hull[idx-2], hull[idx-1], points[i]) <= 0) idx--; hull[idx++] = points[i]; } start = --idx; for(int i=n-2; i>=0; i--){ while(idx-start >= 2 && ccw(hull[idx-2], hull[idx-1], points[i]) <= 0) idx--; hull[idx++] = points[i]; } printf("Convex Hull:\n"); for(int i=0; i<idx-1; i++){ printf("(%d, %d), ", hull[i].x, hull[i].y); } printf("(%d, %d)\n", hull[idx-1].x, hull[idx-1].y); free(hull); } int main(){ Point points[] = {{0,0}, {0,1}, {1,0}, {1,1}, {0.5, 0.5}}; int n = sizeof(points) / sizeof(Point); convex_hull(points, n); return 0; } ``` 该代码中,我们先对点集按照x坐标进行排序,然后逐个加入到凸包中,如果加入新点后不再是凸多边形,则将凸包的最后一个点删除,直到满足要求为止。最后,再从后往前遍历一遍点集,将多余的点删除。 最近问题是指给定平面上的一组点,求出距离最近的两个点之间的距离。下面是一个用蛮力解决最近问题的C语言代码示例: ```c #include <stdio.h> #include <math.h> typedef struct{ double x; double y; } Point; double dist(Point a, Point b){ return sqrt((a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y)); } double closest_pair(Point* points, int n){ double min_dist = 1e9; for(int i=0; i<n; i++){ for(int j=i+1; j<n; j++){ double d = dist(points[i], points[j]); if(d < min_dist) min_dist = d; } } return min_dist; } int main(){ Point points[] = {{0,0}, {0,1}, {1,0}, {1,1}, {0.5, 0.5}}; int n = sizeof(points) / sizeof(Point); double min_dist = closest_pair(points, n); printf("Closest Pair: %lf\n", min_dist); return 0; } ``` 该代码中,我们先枚举所有的点对,计算它们之间的距离,并更新最小距离。最后返回最小距离即可。由于蛮力的时间复杂度为O(N^2),因此该算不适用于大规模的问题。针对最近问题,还可以使用分治或基于数据结构的算进行优化。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

creator_gzw

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值