1.3. 分治法—最近点对问题

2023-10-26

1. 问题描述

给定平面S上n个点,找其中的一对点,使得在n个点组成的所有点对中,该点对间的距离最小

2. 求解过程
  • 划分:将集合S分成两个大小基本相等的子集 S 1 S_1 S1 S 2 S_2 S2
  • 求解子问题:递归地求解两个子问题
  • 合并问题的解(三种情况)
    • 组成S的最近点对的2个点都在 S 1 S_1 S1
    • 组成S的最近点对的2个点都在 S 2 S_2 S2
    • 组成S的最近点对的2个点分别在 S 1 S_1 S1 S 2 S_2 S2
3. 算法思路
  • 预排序:把S中的点分别按x坐标值和y坐标值排序
  • 如果S中包含的点少于4个,则采用蛮力法直接求解
  • 划分
    • 计算S中各点x坐标的中位数m
    • 用垂线L:x=m把S划分成两个大小相等的子集合 S 1 S_1 S1 S 2 S_2 S2 S 1 S_1 S1中的点在L左边, S 2 S_2 S2中的点在L右边
      在这里插入图片描述
  • 求解子问题:递归地在 S 1 S_1 S1 S 2 S_2 S2中找出最近点对( p 1 p_1 p1, p 2 p_2 p2)和( q 1 q_1 q1, q 2 q_2 q2),设其距离分别为 d 1 d_1 d1 d 2 d_2 d2
  • 合并解
    在这里插入图片描述
4. (p,q)的搜索方法
  1. 搜索范围缩小到以L为中心、宽度为2d的临界区内
    在这里插入图片描述

  2. 对于点 p ∈ P p \in P pP,需要考察Q中的各个点和点p之间的距离是否小于d,显然,Q中这样点的y轴坐标一定位于区间[y-d, y+d]之间,即这样的点一定落在一个 d × 2 d d \times 2d d×2d的矩形区域内。而且,根据鸽舍原理可知这样的点不会超过6个
    在这里插入图片描述
    在这里插入图片描述

  3. 临界区内所有点集构成点集R,将其按照y坐标排序,对R中的每个点 r i r_i ri依次考察其后的点 r j r_j rj(最多只要观察紧随其后的7个点),因此,合并步骤可以在线性时间内完成
    在这里插入图片描述

5. 算法伪码

在这里插入图片描述

6. 算法代码
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h> 
//平面点的结构体定义
typedef struct point {
	double x;
	double y;
} point;
//x坐标的比较函数
int compare_x(const void* _a, const void* _b) {
	point* a = (point*)_a;
	point* b = (point*)_b;
	return a->x - b->x;
}
//y坐标的比较函数
int compare_y(const void* _a, const void* _b) {
	point* a = (point*)_a;
	point* b = (point*)_b;
	return a->y - b->y;
}

//计算两点间距离
double distance(point i, point j) {
	return sqrt(pow(i.x - j.x, 2) + pow(j.y - i.y, 2));
}
//求解最近点对
double closestPoints(point* points, int start, int end) {
	double d = INT_MAX;
	//若点集合为空,则直接返回INT_MAX
	if (start == end) {
		return d;
	}
	//若有一个点,则直接计算两点距离
	if (start + 1 == end) {
		return distance(points[start], points[end]);
	}
	//计算中间点
	int mid = (start + end) / 2;
	//递归求解子问题1
	double d1 = closestPoints(points, start, mid);
	//递归求解子问题2
	double d2 = closestPoints(points, mid + 1, end);
	d = fmin(d1, d2);
	point *R = (point*)malloc(sizeof(point)*(end - start + 1));
	int top = 0;
	//构造临界区集合R
	for (int i = start; i <= end; ++i) {
		if (fabs(points[i].x - points[mid].x) < d) {
			R[top++] = points[i];
		}
	}
	//将集合R中的点按y坐标进行快速排序
	/* qsort()函数是C库中实现的快速排序函数
		void qsort(void *base, size_t nitems, size_t size, int (*compar)(const void *, const void*))
		void *base:待排序数组的起始地址
		size_t nitems:待排序数组的元素个数
		size_t size:元素所占的字节数
		int (*compar)(const void *, const void*):比较函数
	*/
	qsort(R, top, sizeof(point), compare_y);
	for (int i = 0; i < top - 1; ++i) {
		for (int j = i + 1; j < top; ++j) {
			if (fabs(points[i].y - points[j].y) < d) {
				double d3 = distance(points[i], points[j]);
				if (d3 < d) {
					d = d3;
				}
			}
		}
	}
	return d;
}

int main() {
	int n;
	printf("请输入点的数量:");
	scanf_s("%d", &n);
	point *points = (point *)malloc(sizeof(point) * n);
	for (int i = 0; i < n; i++) {
		points[i].x = (double)(rand() % 10000)/100 - 50;						//横坐标范围 -50~49
		points[i].y = (double)(rand() % 10000)/100 - 50;						//纵坐标范围 -50~49
		printf("S[%d]=(%lf, %lf)\n", i, points[i].x, points[i].y);
	}
	qsort(points, n, sizeof(point), compare_x);
	printf("最小的距离为%lf", closestPoints(points, 0, n - 1));
	return 0;
}

7. 时间复杂度

在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

1.3. 分治法—最近点对问题 的相关文章

随机推荐

  • java中的多重循环

    多重循环 一个循环体内又包含另一个完整的循环结构 如下 while 循环条件1 循环操作1 while 循环条件2 循环操作2 do 循环操作1 do 循环操作2 while 循环条件2 while 循环条件1 for 循环条件1 循环操作
  • Docker - 使用Docker Compose部署应用

    简介 Docker Compose是一个基于Docker Engine进行安装的Python工具 该工具使得用户可以在一个声明式的配置文件中定义一个多容器的应用 在Docker节点上 以单引擎模式 Single Engine Mode 进行
  • 手写算法-python代码实现Lasso回归

    手写算法 python代码实现Lasso回归 Lasso回归简介 Lasso回归分析与python代码实现 1 python实现坐标轴下降法求解Lasso 调用sklearn的Lasso回归对比 2 近似梯度下降法python代码实现Las
  • 【直达本质讲运放】运放的“第一原理”式定量分析法

    数电 模电那两本书我也完整地翻过一 二遍 诶我为什么用 也 下面就是来点不复杂的 如果是那还不如直接把书的内容粘过来呢 对于运放的定量分析 虚短虚断 就如同 奇变偶不变 一样喜闻乐见的普及 但是对于什么时候用 虚短 什么时候用 虚断 学习的
  • Ridge和Lasso回归

    上周看了看回归方面的知识 顺便复 xue 习一下Ridge 岭回归 和Lasso回归 套索回归 瞅到了一篇英文博客讲得不错 翻译一下 本文翻译自 Ridge and Lasso Regression 本文是一篇Josh Starmer关于
  • 常用网络协议神图

  • 凸优化(一)——Introduction

    Introduction 一 最优化问题的数学表达 在最优问题中 其数学表达往往能化成标准形式 如下 minimizef0 x subject tofi x bi i 1 m begin aligned minimize quad f 0
  • 微信小程序对上传的图片进行裁剪

    背景 使用uniapp中uni chooseImage的裁剪参数crop只能在App中生效 在微信小程序中不生效 实现思路 uni chooseImage打开相册获取图片路径 uni chooseImage OBJECT uni app官网
  • c++面试记录

    1 数组与指针区别 数组 数组是用于储存多个相同类型数据的集合 指针 指针是一个变量 但是它和普通变量不一样 它存放的是其它变量在内存中的地址 赋值 数组 只能一个一个元素的赋值或拷贝 指针 指针变量可以相互赋值 表示范围 数组有效范围就是
  • flink table 使用Kafka Connector处理嵌套json

    使用flink table api 连接kafka 处理json类型数据 单层json处理比较简单 官方或网上都有很多例子 处理嵌套的json数据没什么介绍 处理嵌套json数据主要是schema定义 StreamExecutionEnvi
  • Linux系统之使用yum安装Redis数据库

    Linux系统之使用yum安装Redis数据库 一 redis介绍 1 redis解释 2 redis特点 3 redis使用场景 二 检查系统版本 1 检查系统版本 2 检查内核版本 三 检查yum仓库状态 四 查看系统默认提供的redi
  • mysql数据恢复,使用binlog配置恢复未备份数据

    使用mysqlbinlog配置 恢复数据库 什么是mysqlbinlog binlog是记录所有数据库表结构变更 例如CREATE ALTER TABLE 以及表数据修改 INSERT UPDATE DELETE 的二进制日志 binlog
  • 命令行参数设计

    1 目的 众多通用的小功能 制作为一个小工具 然后通过命令行来进行交互 使用非常的简便 本规范是为了统一命令行参数的设计 使得大家在制作或使用命令行工具时 能够更加有共享 进行会更加方便 2 适用范围 所有命令行工具参数的设计 3 基本原则
  • #SATA# SATA 实际管脚接线图

    前言 概述 实际接线管脚图 PATA 接口 M 2 U 2 AHCI NVMe 概述 SATA是Serial ATA的缩写 即串行ATA 它是一种电脑总线 主要功能是用作主板和大量存储设备 如硬盘及光盘驱动器 之间的数据传输 这是一种完全不
  • 迁移学习:他山之石,可以攻玉【VALSE Webinar】Panel实录

    编者按 迁移学习是机器学习与计算机视觉中的重要研究问题之一 旨在研究如何将一个领域的知识迁移到另外的领域 具有重要的研究意义与应用价值 但迁移学习又会存在哪些局限性 在实际应用中的价值是什么 未来的发展方向在哪里 为此 VALSE Webi
  • docker 数据持久化

    文章目录 定制镜像持久化 需求 实现 数据卷持久化 数据卷简介 数据卷的特性 创建读写数据卷 停止容器后的操作 查看数据卷详情 创建只写数据卷 查看数据卷详情 创建共享数据卷 Dockerfile持久化 创建Dockerfile 构建和运行
  • 大二上学期数据结构课程设计

    1 报数问题 问题描述 有n个小朋友围成一圈玩游戏 小朋友从1至n编号 2号小朋友坐在1号小朋友的顺时针方向 3号小朋友坐在2号小朋友的顺时针方向 1号小朋友坐在n号小朋友的顺时针方向 游戏开始 从1号小朋友开始顺时针报数 接下来每个小朋友
  • 安装TensorFlow遇到no module named ‘tensorflow’问题解决方法

    按照这个博客https blog csdn net qq 16633405 article details 79941696里的步骤安装TensorFlow时遇到no module named tensorflow 虽然作者给出了一个解决方
  • 文本多分类之Doc2Vec实战篇

    本文链接 https blog csdn net weixin 42608414 article details 88391760 版权 在我之前的几篇博客中 我介绍了两种文档向量化的表示方法 如Sklearn的CountVectorize
  • 1.3. 分治法—最近点对问题

    1 问题描述 给定平面S上n个点 找其中的一对点 使得在n个点组成的所有点对中 该点对间的距离最小 2 求解过程 划分 将集合S分成两个大小基本相等的子集 S 1 S 1 S1 和 S