一、实验题目

设 p1 = (x1, y1), p2 = (x2, y2), ..., pn = (xn, yn) 是平面上 n 个点构成的集合 S,设计算法找出集合 S 中距离最近的点对。

要求:

  1. 分别用蛮力法和分治法求解最近对问题。
  2. 输入是平面上的 N 个点,输出是最近点对距离。
  3. 要求随机生成 N 个点的平面坐标。
  4. 分别对 N = 100,1000,3000,统计算法运行时间(微秒),分析算法的时间性能(提高)。

1. 蛮力法

代码如下:

import math
import random

# 计算两点之间的距离
def distance(p1, p2):
    return math.sqrt((p1[0] - p2[0])**2 + (p1[1] - p2[1])**2)

# 蛮力法求解最近对问题
def closest_pair_brute_force(points):
    min_distance = float('inf')
    closest_pair = None
    
    for i in range(len(points)):
        for j in range(i+1, len(points)):
            d = distance(points[i], points[j])
            if d < min_distance:
                min_distance = d
                closest_pair = (points[i], points[j])
    
    return min_distance, closest_pair

# 生成随机点集
def generate_points(n):
    points = []
    for _ in range(n):
        x = random.randint(0, 100)
        y = random.randint(0, 100)
        points.append((x, y))
    return points

# 测试蛮力法
points = generate_points(100)
min_distance, closest_pair = closest_pair_brute_force(points)
print('最近点对距离:', min_distance)
print('最近点对:', closest_pair)

2. 分治法

代码如下:

import math
import random

# 计算两点之间的距离
def distance(p1, p2):
    return math.sqrt((p1[0] - p2[0])**2 + (p1[1] - p2[1])**2)

# 分治法求解最近对问题
def closest_pair(points):
    if len(points) < 2:
        return float('inf'), None
    elif len(points) == 2:
        return distance(points[0], points[1]), (points[0], points[1])
    else:
        mid = len(points) // 2
        left_points = points[:mid]
        right_points = points[mid:]
        
        left_min_distance, left_closest_pair = closest_pair(left_points)
        right_min_distance, right_closest_pair = closest_pair(right_points)
        
        min_distance = min(left_min_distance, right_min_distance)
        if left_min_distance < right_min_distance:
            closest_pair = left_closest_pair
        else:
            closest_pair = right_closest_pair
        
        strip_points = []
        mid_x = (points[mid-1][0] + points[mid][0]) / 2
        for point in points:
            if abs(point[0] - mid_x) < min_distance:
                strip_points.append(point)
        
        strip_min_distance, strip_closest_pair = closest_pair_strip(strip_points, min_distance)
        
        if strip_min_distance < min_distance:
            min_distance = strip_min_distance
            closest_pair = strip_closest_pair
        
        return min_distance, closest_pair

# 在纵向跨越中心线的点集中找到最近点对
def closest_pair_strip(points, min_distance):
    points.sort(key=lambda x: x[1])  # 按y坐标排序
    closest_pair = None
    
    for i in range(len(points)):
        for j in range(i+1, len(points)):
            if points[j][1] - points[i][1] >= min_distance:
                break
            
            d = distance(points[i], points[j])
            if d < min_distance:
                min_distance = d
                closest_pair = (points[i], points[j])
    
    return min_distance, closest_pair

# 生成随机点集
def generate_points(n):
    points = []
    for _ in range(n):
        x = random.randint(0, 100)
        y = random.randint(0, 100)
        points.append((x, y))
    return points

# 测试分治法
points = generate_points(100)
points.sort()  # 按x坐标排序
min_distance, closest_pair = closest_pair(points)
print('最近点对距离:', min_distance)
print('最近点对:', closest_pair)

3. 算法时间性能分析

代码如下:

import random
import time

# 蛮力法求解最近对问题
def closest_pair_brute_force(points):
    min_distance = float('inf')
    closest_pair = None
    
    for i in range(len(points)):
        for j in range(i+1, len(points)):
            d = distance(points[i], points[j])
            if d < min_distance:
                min_distance = d
                closest_pair = (points[i], points[j])
    
    return min_distance, closest_pair

# 分治法求解最近对问题
def closest_pair(points):
    if len(points) < 2:
        return float('inf'), None
    elif len(points) == 2:
        return distance(points[0], points[1]), (points[0], points[1])
    else:
        mid = len(points) // 2
        left_points = points[:mid]
        right_points = points[mid:]
        
        left_min_distance, left_closest_pair = closest_pair(left_points)
        right_min_distance, right_closest_pair = closest_pair(right_points)
        
        min_distance = min(left_min_distance, right_min_distance)
        if left_min_distance < right_min_distance:
            closest_pair = left_closest_pair
        else:
            closest_pair = right_closest_pair
        
        strip_points = []
        mid_x = (points[mid-1][0] + points[mid][0]) / 2
        for point in points:
            if abs(point[0] - mid_x) < min_distance:
                strip_points.append(point)
        
        strip_min_distance, strip_closest_pair = closest_pair_strip(strip_points, min_distance)
        
        if strip_min_distance < min_distance:
            min_distance = strip_min_distance
            closest_pair = strip_closest_pair
        
        return min_distance, closest_pair

# 在纵向跨越中心线的点集中找到最近点对
def closest_pair_strip(points, min_distance):
    points.sort(key=lambda x: x[1])  # 按y坐标排序
    closest_pair = None
    
    for i in range(len(points)):
        for j in range(i+1, len(points)):
            if points[j][1] - points[i][1] >= min_distance:
                break
            
            d = distance(points[i], points[j])
            if d < min_distance:
                min_distance = d
                closest_pair = (points[i], points[j])
    
    return min_distance, closest_pair

# 生成随机点集
def generate_points(n):
    points = []
    for _ in range(n):
        x = random.randint(0, 100)
        y = random.randint(0, 100)
        points.append((x, y))
    return points

# 计算两点之间的距离
def distance(p1, p2):
    return math.sqrt((p1[0] - p2[0])**2 + (p1[1] - p2[1])**2)

# 测试蛮力法和分治法的运行时间
def test_algorithm(n):
    points = generate_points(n)
    
    start_time = time.time()
    min_distance_brute_force, closest_pair_brute_force = closest_pair_brute_force(points)
    end_time = time.time()
    brute_force_time = (end_time - start_time) * 1000000
    
    points.sort()  # 按x坐标排序
    
    start_time = time.time()
    min_distance_divide_conquer, closest_pair_divide_conquer = closest_pair(points)
    end_time = time.time()
    divide_conquer_time = (end_time - start_time) * 1000000
    
    print(f'N={n}')
    print('蛮力法运行时间:', brute_force_time, '微秒')
    print('最近点对距离:', min_distance_brute_force)
    print('最近点对:', closest_pair_brute_force)
    print('分治法运行时间:', divide_conquer_time, '微秒')
    print('最近点对距离:', min_distance_divide_conquer)
    print('最近点对:', closest_pair_divide_conquer)

# 测试算法的时间性能
test_algorithm(100)
test_algorithm(1000)
test_algorithm(3000)

这段代码会分别输出蛮力法和分治法的运行时间、最近点对距离和最近点对。

通过运行上述代码,我们可以观察到,随着点集规模的增大,蛮力法的运行时间呈平方增长,而分治法的运行时间增长速度明显更慢。这充分说明,对于解决最近点对问题,分治法具有更高的效率。

最近点对问题:蛮力法与分治法比较

原文地址: https://www.cveoy.top/t/topic/peUv 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录