【问题标题】:Optimal way to find number of operation required to convert all K numbers to lie in the range [L,R] (i.e. L≤x≤R)找到将所有 K 数转换为位于 [L,R] 范围内所需操作数的最佳方法(即 L≤x≤R)
【发布时间】:2015-05-21 09:00:38
【问题描述】:

我正在解决这个需要一些优化技术的问题 解决这个问题。我能想到的蛮力方法只需要 组合学。

给定一个由 n 个整数组成的数组 A。我们称整数“好” 如果它位于 [L,R] 范围内(即 L≤x≤R)。我们需要确定我们是否 从数组中取出任何 K 个整数,其中至少一个应该是 好整数。

为了实现这一点,在一次操作中,我们可以 将数组的任何元素增加/减少一。

我们需要的最少操作数是多少? 固定k?”

即 k=1 到 n。

input:
L  R
1  2

A=[ 1 3 3 ]

output:
for k=1 : 2 
for k=2 : 1
for k=3 : 0

对于 k=1,您必须将两个 3 都转换为 2 以确保如果 你选择3个整数中的任何一个,选择的整数都是好的。

对于 k=2,一种可能的方法是将 3 之一转换为 2。

对于 k=3,不需要任何操作,因为 1 是一个很好的整数。

【问题讨论】:

  • 输入数组的大小是多少?
  • 提示!使用 DP 进行预处理
  • @PhamTrung n≤10^5 和 A[i]≤10^9..
  • @therealprashant 最初我想到了 DP,但无法想出一个结构。你认为什么可以作为 DP 的起点?
  • @PhamTrung 我已经写过它的 k= 1 到 N

标签: arrays algorithm combinatorics


【解决方案1】:

正如 burnpanck 在他的回答中所解释的那样,为了确保当您选择数组中的任何 k 个元素时,并且其中至少有一个在 [L,R] 范围内,我们需要确保至少有n - k + 1 数组中 [L,R] 范围内的数字。

因此,首先,对于每个元素,我们计算使该元素成为 valid 元素(在 [L,R] 范围内)的成本,并将这些成本存储在数组 cost 中。

我们注意到:

  • 对于k = 1,最小成本是数组cost的总和。

  • 对于 k = 2,最小成本是 cost 的总和减去最大元素。

  • 对于 k = 3,最小成本是 cost 的总和,减去两个最大元素。

    ...

所以,我们需要一个prefixSum 数组,它的第i 个位置是排序 cost 数组从0 到第i 个的总和。

计算prefixSum后,我们可以在O(1)中为每个k回答结果

这是Java中的算法,注意时间复杂度是O(n logn)

int[]cost = new int[n];
for(int i = 0; i < n; i++)
    cost[i] = //Calculate min cost for element i
Arrays.sort(cost);
int[]prefix = new int[n];
for(int i = 0; i < n; i++)
   prefix[i] = cost[i] + (i > 0 ? prefix[i - 1] : 0);

for(int i = n - 1; i >= 0; i--)
   System.out.println("Result for k = " + (n - i) + " is " + prefix[i]); 

【讨论】:

  • 我明白了,只是解释一下为什么会这样——“对于k = 2,最小成本是成本之和,减去最大元素。”。我的意思是为什么减去最大元素。我想不出有什么关系。谢谢
  • @Ashish 因为,当 k = 2 时,我们需要使数组中的所有元素都成为有效元素,除了一个元素,我们可以选择那个元素。因此,为了获得最低成本,我们需要选择成本最高的元素。
  • 最后......感谢您提出所有这些问题......现在我在想我怎么会错过这一点......但是一旦你知道了解决方案,所有问题看起来都很容易。 .. :)
  • @Ashish 很高兴这个帮助 :),如果它回答了你的问题,你能接受它吗?
【解决方案2】:

为了确保从挑选 k 个元素中至少会给出一个有效的意思,你的集合中应该有不超过 k-1 个无效的意思。因此,您需要找到使足够多的元素有效的最短方法。我会这样做:在一次传递中,生成一个映射,计算集合中有多少元素需要 $n$ 操作才能生效。那么,你显然想取那些需要最少操作的元素,所以按照所需操作数量的升序取所需数量的元素,并对操作数量求和。

在python中:

def min_ops(L,R,A_set):
    n_ops = dict()  # create an empty mapping
    for a in A_set:   # loop over all a in the set A_set
        n = max(0,max(a-R,L-a))  # the number of operations requied to make a valid
        n_ops[n] = n_ops.get(n,0) + 1  # in the mapping, increment the element keyed by *n* by ones. If it does not exist yet, assume it was 0.
    allret = []   # create a new list to hold the result for all k
    for k in range(1,len(A_set)+1):  # iterate over all k in the range [1,N+1) == [1,N]
        n_good_required = len(A_set) - k + 1
        ret = 0
        # iterator over all pairs of keys,values from the mapping, sorted by key.
        # The key is the number of ops required, the value the number of elements available
        for n,nel in sorted(n_ops.items()):   
            if n_good_required:
               return ret
            ret += n * min(nel,n_good_required)
            n_good_required -= nel
        allret.append(ret)  # append the answer for this k to the result list
    return allret

举个例子:

A_set = [1,3,3,6,8,5,4,7]
L,R = 4,6

对于每个 A,我们找出需要多少操作才能使其有效:

n = [3,1,1,0,2,0,0,1]            

(即 1 需要 3 个步骤,3 需要 1 个,依此类推) 然后我们计算它们:

n_ops = {
    0: 3,   # we already have three valid elements
    1: 3,   # three elements that require one op
    2: 1,
    3: 1,   # and finally one that requires 3 ops
}

现在,对于每个 k,我们找出集合中需要多少个有效元素, 例如对于 k = 4,我们需要在 8 个集合中最多 3 个无效,因此我们需要 5 个有效。

因此:

ret = 0
n_good_requied = 5
with n=0, we have 3 so take all of them
ret = 0
n_good_required = 2
with n=1, we have 3, but we need just two, so take those
ret = 2
we're finished

【讨论】:

  • 您能否提供更多见解。可能是带有示例的演示。谢谢
  • 我对python不熟悉。你能把cmets放在一边你的代码,这样每个不懂python的人都能更容易地给你点清楚。
  • 如果你能用上面的例子演示你的代码以及它如何得到正确的答案,我们会很好。谢谢
  • n_ops = { 0: 3, # 我们已经有三个有效元素 1: 3, # 三个需要一个操作的元素 2: 1, 3: 1, # 最后一个需要 3 个操作 }需要 1 次操作的 3 个元素是什么。我只能看到一个元素,即 3
  • 我以与 burnpanck 相同的方式理解最初的问题:从未指定您选择的 K 个整数必须在初始数组中彼此相邻。因此,当且仅当您的数组中最多有 k-1 个“坏”整数时,您确保始终为任意选择获得至少一个好的整数。如果这不是故意的,请编辑问题以澄清这一点:)
猜你喜欢
  • 2020-11-07
  • 1970-01-01
  • 2021-09-21
  • 2021-10-16
  • 1970-01-01
  • 2023-02-07
  • 1970-01-01
  • 1970-01-01
  • 2019-04-20
相关资源
最近更新 更多