将一组分成具有最小移动次数的k组

时间:2012-09-12 10:58:42

标签: algorithm

您有一组 n 对象,其中给出了整数位置。对象的是一组位于同一位置的对象(不一定是该位置的所有对象:单个位置可能有多个组)。对象可以向左或向右移动,目标是移动这些对象以形成 k 组,并且移动最小距离。

例如:

  • 初始位置为[4,4,7], k = 3:最低成本为0.
  • [4,4,7]和 k = 2:最低成本为0
  • [1,2,5,7]和 k = 2:最低费用为1 + 2 = 3

我一直在尝试使用贪婪的方法(通过计算哪个移动最短),但这不起作用,因为每次移动都涉及两个可以移动的元素。我还没有能够制定动态编程方法,但我正在研究它。

4 个答案:

答案 0 :(得分:3)

此问题是k-medians problem的一维实例,可以如下所述。给定一组点x_1 ... x_n,将这些点划分为k个集合S_1 ... S_k,并以最小化| x_i - y_f(i)|的所有x_i之和的方式选择k个位置y_1 ... y_k。 ,其中y_f(i)是与分配了x_i的集相对应的位置。

由于中位数是population minimizer for absolute distance (i.e. L_1 norm),因此每个位置y_j将是相应集合S_j中元素x的中值(因此名称为k-medians)。由于您正在查看整数值,因此技术性如果S_j包含偶数个元素,则中位数可能不是整数,但在这种情况下,选择中位数上方或下方的下一个整数将给出相同的总和绝对距离。

解决k-medians的标准启发式(以及相关且更常见的k-means问题)是迭代的​​,但不能保证产生最佳或甚至好的解决方案。解决一般度量空间的k-中值问题是NP难的,找到k-中值的有效近似是一个开放的研究问题。例如,谷歌搜索“k-medians近似”将导致一堆文件给出近似方案。 http://www.cis.upenn.edu/~sudipto/mypapers/kmedian_jcss.pdf http://graphics.stanford.edu/courses/cs468-06-winter/Papers/arr-clustering.pdf

在一个方面,事情变得更容易,您可以使用动态编程方法。在this paper中描述了相关的一维k均值问题的DP解决方案,并且R中的源代码可用here。有关详细信息,请参阅该文章,但这个想法基本上与@SajalJain提出的相同,并且可以很容易地适应解决k-medians问题而不是k-means。对于j <= k且m <= n,令D(j,m)表示对x_1 ... x_m的最优j-中值解的成本,其中假设x_i按排序顺序。我们有复发

D(j,m) = min (D(j-1,q) + Cost(x_{q+1},...,x_m)

其中q的范围从j-1到m-1,Cost等于距中位数的绝对距离之和。通过Cost的朴素O(n)实现,这将产生针对整个问题的O(n ^ 3k)DP解决方案。但是,这可以改进为O(n ^ 2k),因为Cost可以在恒定时间内更新,而不是每次从头开始计算,使用以下事实:对于排序序列:

Cost(x_1,...,x_h) = Cost(x_2,...,x_h) + median(x_1...x_h)-x_1   if h is odd
Cost(x_1,...,x_h) = Cost(x_2,...,x_h) + median(x_2...x_h)-x_1   if h is even

有关详细信息,请参阅文章。除了Cost函数的更新不同之外,k-medians的实现与k-means的实现相同。 http://journal.r-project.org/archive/2011-2/RJournal_2011-2_Wang+Song.pdf

答案 1 :(得分:1)

据我了解,问题是:

我们在一条线上有n个点。 我们想把k位置放在线上。我称之为目的地。 将n个点中的每一个移动到k个目的地中的一个,因此距离之和最小。我称这笔金额为总费用。 目的地可以重叠。

一个显而易见的事实是,对于每个点,我们应该寻找左边最近的目的地和右边最近的目的地,并选择最近的目的地。

另一个重要的事实是所有目的地都应该在这些点上。因为我们可以在线上向右或向左移动它们以达到一个点而不增加总距离。

通过这些事实考虑以下DP解决方案:

DP [i] [j]表示第一个i点所需的最小总成本,当我们只能使用j个目的地时,必须将目的地放在第i个点上。

计算DP [i] [j]在第i个点之前固定目的地(我们有选择),并且对于每个选择(例如第k个点)计算i之间的点所需的距离th点和新点加(第k点)。用DP [k] [j - 1]添加它,找到所有k的最小值。

计算初始状态(例如j = 1),最终答案留作练习!

答案 2 :(得分:0)

任务0 - 按非递减顺序排列对象的位置

让我们将'center'定义为对象的位置shifted to.

现在我们有两个观察结果;

  1. For N positions the 'center' would be the position which is nearest to the mean of these N positions.例如,让1,3,6,10为位置。然后意味着= 5.最近的位置是6.因此这些元素的中心是6.这使得我们在所有元素需要被分组为1组时以最小的移动成本获得位置。

  2. 让N个位置“最佳地”分组为K个组。 When N+1 th object is added,那么它只会打扰第K组,即first K-1 groups will remain unchanged.

  3. 从这些观察中,我们构建了一种动态编程方法。

    Let Cost[i][k] and Center[i][k] be two 2D arrays. 
    Cost[i][k] = minimum cost when first 'i' objects are partitioned into 'k' groups
    Center[i][k] stores the center of the 'i-th' object when Cost[i][k] is computed.
    

    Let {L} be the elements from i-L,i-L+1,..i-1 which have the same center.
    (Center[i-L][k] = Center[i-L+1][k] = ... = Center[i-1][k])
    这些是第i个元素计算中需要考虑的唯一对象(来自观察2)

    现在

    Cost[i][k] will be 
    min(Cost[i-1][k-1] , Cost[i-L-1][k-1] + computecost(i-L, i-L+1, ... ,i))
    Update Center[i-L ... i][k]
    

    computecost()可以通过找到中心(来自观察1)来轻松找到

    时间复杂度:

    Sorting O(NlogN)
    Total Cost Computation Matrix = Total elements * Computecost = O(NK * N)
    Total = O(NlogN + N*NK) = O(N*NK)
    

答案 3 :(得分:0)

让我们看看k = 1。

对于k = 1和n odd,所有点都应移动到中心点。对于k = 1和n even,所有点都应移动到中心点或它们之间的任何点。 “中心”是指任意一方的点数,即中位数。

你可以看到这一点,因为如果选择一个目标点x,其右边的点多于它的左边,那么x右边的新目标1将导致成本降低(除非只有一个指向右边而不是左边,目标点是一个点,在这种情况下,n是偶数,目标在两个中心点上/之间。)

如果您的积分已经排序,则这是O(1)操作。如果没有,我相信它是O(n)(通过订单统计算法)。

一旦找到了所有点都移动到的位置,找到成本就是O(n)。

因此无论点是否排序,这都是O(n)。