如何求解无限轴点选址及基于DP的路灯放置代码实现问题?
咱们先逐个解决你的两个问题,先从抽象的无限轴问题说起,再聚焦到实际的路灯规划动态实现上。
问题一:无限轴上选N个点使M个点的最近距离和最小
首先明确前提:我默认你说的是给定M个固定点,要在无限轴上选N个点(可任意位置),让每个M点到最近的N点的距离总和最小。如果理解有误,你可以补充说明~
最优解法分两步:
- 第一步:把M个点按坐标从小到大排序。因为无限轴无边界限制,最优分组一定是连续的(如果分组不连续,比如把中间点分到左组、两边点分到右组,会额外增加距离和,连续分组是最优选择)。
- 第二步:用动态规划将排序后的点划分成N个连续组,每组选中位数作为组的代表点,让各组的距离和总和最小。
为什么选中位数?这是经典结论:对于一组点,曼哈顿距离和最小的点就是该组的中位数。比如点[1,3,5],选3的距离和是4,选其他点的距离和都会更大。
动态规划核心逻辑
- 状态定义:
dp[i][k]表示前i个M点,用k个选定点时的最小距离和。 - 状态转移:
dp[i][k] = min(dp[j][k-1] + cost(j+1, i)),其中j的范围是k-1 <= j < i(前j个点至少需要k-1个选定点,每组至少1个点),cost(a,b)表示第a到第b个M点组成一组,选中位数时的距离和。 - 预处理
cost数组:提前计算所有区间的距离和,避免重复计算,提升效率。
问题二:道路房屋路灯规划的动态实现
这个问题更具体:路灯必须安装在房屋位置,相邻房屋间距不同,我们用动态规划一步步实现最优解。
1. 问题转化与准备
首先将房屋位置整理成有序数组pos(道路上的房屋是线性排列的,提前按坐标排序),比如pos[0], pos[1], ..., pos[N-1],我们要选M个位置放路灯,让所有房屋到最近路灯的距离总和最小。
2. 动态规划核心设计
状态定义
dp[k][i] 表示用k盏路灯覆盖前i+1栋房屋(即pos[0]到pos[i])的最小距离和。
预处理cost数组
我们需要提前计算cost[a][b]:覆盖第a到第b栋房屋(0-based)用1盏路灯的最小距离和。根据中位数最优的结论,我们在a到b的房屋中选中位数位置放路灯,用前缀和快速计算距离和:
- 先预处理前缀和数组
prefix_sum,prefix_sum[i]表示pos[0]到pos[i-1]的坐标和,方便快速计算区间和。 - 对于区间
[a,b],找到中位数位置m = a + (b - a) // 2,计算:- 左边房屋到
pos[m]的距离和:pos[m]*(m - a + 1) - (prefix_sum[m+1] - prefix_sum[a]) - 右边房屋到
pos[m]的距离和:(prefix_sum[b+1] - prefix_sum[m+1]) - pos[m]*(b - m) cost[a][b]就是左右距离和的总和。
- 左边房屋到
状态转移与初始化
- 初始化:
dp[1][i] = cost[0][i],表示用1盏路灯覆盖前i+1栋房屋的最小距离和。 - 状态转移:对于
k >= 2,dp[k][i] = min(dp[k-1][j] + cost[j+1][i]),其中j的范围是k-2 <= j < i(前j栋房屋用k-1盏路灯,至少需要k-1栋房屋)。 - 最终答案:
dp[M][N-1],即覆盖所有N栋房屋用M盏路灯的最小距离和。
3. Python代码实现示例
def min_streetlight_distance(pos, M): N = len(pos) pos.sort() # 确保房屋位置按道路顺序排列 # 预处理前缀和数组 prefix_sum = [0] * (N + 1) for i in range(N): prefix_sum[i+1] = prefix_sum[i] + pos[i] # 预处理cost[a][b]:覆盖a到b栋房屋用1盏路灯的最小距离和 cost = [[0] * N for _ in range(N)] for a in range(N): for b in range(a, N): # 找到区间[a,b]的中位数位置 m = a + (b - a) // 2 # 计算左边房屋到中位数的距离和 sum_left = pos[m] * (m - a + 1) - (prefix_sum[m+1] - prefix_sum[a]) # 计算右边房屋到中位数的距离和 sum_right = (prefix_sum[b+1] - prefix_sum[m+1]) - pos[m] * (b - m) cost[a][b] = sum_left + sum_right # 初始化dp数组,初始值设为无穷大 dp = [[float('inf')] * N for _ in range(M+1)] # 填充1盏路灯的情况 for i in range(N): dp[1][i] = cost[0][i] # 填充多盏路灯的情况 for k in range(2, M+1): # 至少需要k栋房屋才能放k盏路灯,所以i从k-1开始 for i in range(k-1, N): # 前j栋房屋用k-1盏路灯,j至少为k-2(对应k-1栋房屋) for j in range(k-2, i): if dp[k-1][j] + cost[j+1][i] < dp[k][i]: dp[k][i] = dp[k-1][j] + cost[j+1][i] return dp[M][N-1] # 测试示例 pos = [1, 3, 5, 7, 9] M = 2 print(min_streetlight_distance(pos, M)) # 输出:6
4. 优化思路
如果N很大(比如N>1000),O(MN²)的时间复杂度会超时,此时可以用四边形不等式优化(或Knuth优化),因为cost函数满足四边形不等式,能将时间复杂度降到O(MN),适合大规模数据场景。
内容的提问来源于stack exchange,提问作者K_peanutButter
相关产品推荐
相关产品推荐

