这个问题在接受采访时向我询问,并且令人尴尬地暴露了我在动态编程方面的缺点。如果有人可以帮我解决这个问题,我将不胜感激。此外,如果您能够在设计解决方案的过程中解释您的思维过程对我(以及其他人)非常有帮助,因为当我看到使用动态编程范例的解决方案但我很难理解时跟我一起。
不用多说,这是我被问到的问题。
在实线上给定i
整数X
并设置k
点x1
,x2
,... xk
,请选择来自i
集的X
点,以便使用动态编程最小化X
中每个点到i
中的点的距离之和。
答案 0 :(得分:7)
对于大多数DP问题,我尝试找到一种减少与征服的关系。也就是说,我可以通过每一步切断问题大小的关系(如分而治之,但通常不会分解问题,只是删除了一小部分)。在这个问题中(和许多其他问题一样)我们可以做一个非常简单的观察:第一个点在i
点的集合中,或者它不是。
一些符号:假设X = {x 1 ,x 2 ,...,x k },并表示减少设置X n = {x n ,x n + 1 ,...,x k }。< / p>
因此,观察结果是x 1 是i
点之一,或者不是。让我们调用我们的i
- 设置查找函数MSD(i
,X k )(最小距离之和)。我们可以表达如下切入观察:
MSD(i
,X k )= MSD(i-1
,X k-1 )U {x 1 }或MSD(i
,X k-1 )
我们可以通过实现一种简单的方法来检查“两个或两个”部分,它实际上是检查这两个选项中的哪一个:我们遍历集合X并计算距离之和,并检查哪个实际上更小。我们注意到,此检查的运行时间为ki
,因为我们将天真地遍历每个k
点,并抓住距离i
中的点的最小距离}。
我们对基本案例做了两个简单的观察:
MSD(i
,X i )= X i
MSD(0
,X n )= {}
首先,在查看一组i
的{{1}}点时,我们显然只需要整套。
第二个是当在集合中寻找没有点时,我们返回空集。这可以有效地确保MSD返回大小为i
的集合(根据我们上面对MSD的定义,对于i
和归纳为真的情况是正确的。)
就是这样。那将找到合适的集合。
运行时复杂性受i=0
限制,其中step是我们从上方O(ik * step)
检查的。这是因为MSD将在O(ik)
和X 1 - X k 之间的参数上运行,这是0-i
个可能的参数的总和
这使我们的运行时间为O((ik) 2 )。
以下部分基于我对OP问题的理解。我不确定X中每个点与i大小子集的距离是否是子集中每个其他点的每个点的距离之和,或者距离的总和X 中的每个点来自子集本身 即x中x的西格玛(子集中每个点的距离之和)或x中x的西格玛(距子集x的距离,即从子集到子集中任意点的最小距离)
我假设后者。
我们可以通过优化上面的ik
检查来减少运行时间。我们注意到元素实际上是排序的(虽然在当前符号中是相反的顺序),因为当我们添加它们时,我们总是从右侧进行。假设它们已经开始排序,它们将一次退出MSD例程。如果他们没有排序,我们可以对它们进行排序,无论如何都只需O(ik)
。
一旦排序,检查每个点与集合中一个点的距离将为O(klogk)
,因为对于每个点,我们进行二分搜索。这使得总运行时间为k * logi
= O(k 2 * ilogi)。
最后,我们可以表示为O(k 3 logk)。不是最快的解决方案,而是解决方案。
我确信还有更多的优化,但那是我的2c。