算法设计--蛮力法&&分治法求最近对问题(C++实现)

最近对问题?

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





  • 1
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
最大子段和问题是指在一个数列中找到一个子序列,使得该子序列中所有元素的和最大。以下是三种常见的算法实现: 1. 蛮力 蛮力是最朴素的解,它的时间复杂度为 $O(n^2)$。具体实现如下: ```c++ int maxSubArray(int nums[], int n) { int ans = INT_MIN; for (int i = 0; i < n; i++) { int sum = 0; for (int j = i; j < n; j++) { sum += nums[j]; ans = max(ans, sum); } } return ans; } ``` 2. 分治法 分治法的时间复杂度为 $O(n\log n)$,它将问题分成三个部分:解左半部分的最大子段和、解右半部分的最大子段和、解跨越中点的最大子段和。具体实现如下: ```c++ int maxSubArray(int nums[], int left, int right) { if (left == right) return nums[left]; int mid = left + (right - left) / 2; int leftMax = maxSubArray(nums, left, mid); int rightMax = maxSubArray(nums, mid + 1, right); int crossMax = nums[mid]; int sum = nums[mid]; for (int i = mid - 1; i >= left; i--) { sum += nums[i]; crossMax = max(crossMax, sum); } sum = crossMax; for (int i = mid + 1; i <= right; i++) { sum += nums[i]; crossMax = max(crossMax, sum); } return max(leftMax, max(rightMax, crossMax)); } ``` 3. 动态规划 动态规划的时间复杂度为 $O(n)$,它定义了一个状态数组 $dp$,其中 $dp[i]$ 表示以 $i$ 结尾的最大子段和。具体实现如下: ```c++ int maxSubArray(int nums[], int n) { int dp[n]; dp[0] = nums[0]; int ans = nums[0]; for (int i = 1; i < n; i++) { dp[i] = max(dp[i - 1] + nums[i], nums[i]); ans = max(ans, dp[i]); } return ans; } ``` 以上是三种常见的算法实现,需要注意的是,在实际应用中,我们还可以使用其他优化方,如前缀和、后缀和、单调栈等,以进一步提高算法效率。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

小巫技术博客

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

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

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

打赏作者

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

抵扣说明:

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

余额充值