Hard
要求解这道题,不能陷入到题目的描述当中,需要提取题目表述,简化条件。
houses
数组是无序的,首先需要先将houses
排序i
个房子里面插入k
个邮筒。可以转化成,将houses
数组,分成k
份,k
置于这几个分组中间。使得距离和最小dp[i][j]
表示,i
个数字这个区间划分j
份的最小距离dp[n][k]
为什么是中位数
对于一个数组,一个邮筒的情况。为什么放置在中位数节点是距离和最小的情况。我们可以一对一对的看,假如房子的数量是2个,那么我们放在中间任意的位置距离和都是一样的。假如房子数量是3,那我们放在中间那个房子的距离和是最小的。扩展,房子的偶数个,邮箱放在对中间的一对房子的任意位置,距离和最小。房子个数是奇数个,邮箱放在中间那个房子的节点位置,距离和最小
结论:一个邮箱的情况,只要放在中位数节点,就可以值距离和最小
状态转移
对于最后一个邮箱来说,
最大的负责范围是第j-1
个房间,到i
的房间,最坏就是前面的一个邮箱管一个房子。那最后一个就得剩下的都管
最小的负责范围是第i
个房间,前面的房间,都被前边的邮箱管走了,只用管最后一个房间就行了
所以状态转移方程为
\(dp[i][j]=min(dp[t-1][j-1] + distance(t,i), dp[i][j])\) \(i>=t>=j-1\)
尝试写一下代码,AC!真不容易,主要是边界条件还是不熟,还是要单步慢慢调,还是太弱鸡阿。
python3
class Solution:
# houses在区间[i,j]中放置一个邮筒的最小距离和
def distance(self, houses, i, j):
dis = 0
m = (i+j) // 2
for k in range(i,j+1):
dis += abs(houses[k-1] - houses[m-1])
return dis
def minDistance(self, houses: List[int], k: int) -> int:
houses.sort()
#定义dp数组,dp[i][j]表示i个数前分成j组的最小距离
dp = [[math.inf for _ in range(k+1)] for _ in range(len(houses)+1)]
for h in range(1, len(houses) + 1):
dp[h][1] = self.distance(houses, 1, h)
for i in range(1, len(houses)+1):
for j in range(2, k+1):
for t in range(j-1, i+1):
dis = self.distance(houses, t, i)
dp[i][j] = min(dp[i][j], dp[t-1][j-1] + dis)
return dp[len(houses)][k]