无法理解算法

时间:2016-06-13 18:45:52

标签: algorithm greedy

这是问题的链接 https://www.hackerrank.com/challenges/equal

我读了它的社论并且无法理解它。如果你没有对hackerrank做任何说明,那么肯定你不会看到它的社论,所以这里有一些社论。

  

这相当于说,christy可以带走巧克力   一个同事按1,2或5,同时保持其他人的巧克力不受影响       让我们考虑减少同事的巧克力作为一种手术。为了减少操作次数,我们应该尝试使每个同事的巧克力数量等于组中的最小值(分钟)。我们必须通过(A [i] - min)减少第i个人A [i]的巧克力数量。设这个值为x。

This can be done in k operations.

k = x/5 +(x%5)/2 + (x%5)%2 

从这里我无法理解

  

设f(min)是对所有同事进行减少的操作的总和   他们每个巧克力都要分钟。但是,有时f(min)可能不会   总是给出正确的答案。

时也可能是这种情况
f(min) > f(min-1)

f(min) < f(min-5)
  

因为f(min-5)N次操作超过f(min),其中N是数字   同事。因此,如果

A = {min,min-1,min-2,min-3,min-4}
then f(A) <= f(min) < f(min-5)

有人可以帮助我理解为什么这需要检查f(min),f(min-1),...,f(min-4)

1 个答案:

答案 0 :(得分:8)

考虑案例A = [1,5,5]

正如社论所说,用4(2减2)次操作将A更改为[1,1,1]是最佳的直观,但最好将其更改为[0 ,0,0]与3(1减1,2,2减5)操作。

因此,如果min = minimum element in array,则将所有元素更改为min可能不是最佳的。

您不理解的部分是为了迎合这种情况,我们知道min可能不是最佳的min-x可能更好,但x有多大?那么 4 。社论说如果我们知道x最多为4,我们可以简单地强行minmin-1 ... min-4来查看哪一个是最小的想得太多。

x&lt; = 4

的推理(不证明!)

如果x> = 5,那么你必须对所有绝对不值得的元素使用额外的N类型3(减去5)操作。

基本上这不是操作类型的问题,而是因为你需要对所有元素使用相同的操作,在你这样做之后,问题不会减少,相对差异在于当你想要将相对差异设为0时,元素仍然是相同的,你只需花费 N 操作。

换句话说,如果x> = 5,则x-5必须是目标的更佳选择,实际上x%5必须是最佳目标。

(以下是TL; DR部分:版本2)如果您对证明不感兴趣,请跳至上一部分

在编写原始解决方案的过程中,我怀疑 x <= 2 ,我试图在HackerRank上提交代码,该代码仅检查f(min-x) where x <= 2的最小值,并且它获得了成功。

更正式地说,我声称

  

如果5&gt; (z-min)%5> = 3且(z-min&#39;)%5 == 0,然后F(min&#39;)&lt; F(分钟)   其中min&#39; = min-x表示x <= 2,F(k)= min#操作元素z成为k

(请注意表示法,我使用的是F(),它与问题f()的含义不同

以下是证据:

如果(z-min)%5 = 1 or 2,那么它至少需要(z-min)/5 + 1次操作,而(z-min')%5 == 0 needs (z-min')/5 = (z-min)/5 + 1操作则意味着F(min') = F(min)

如果(z-min)%5 == 3 or 4,那么它至少需要(z-min)/5 + 2次操作,而(z-min')%5 == 0 needs (z-min')/5 = (z-min)/5 + 1操作则意味着F(min') < F(min) (or F(min') = F(min)+1)

所以我们证明

  

如果5&gt; (z-min)%5> = 3且(z-min&#39;)%5 == 0,然后F(min&#39;)&lt; F(分钟)   其中min&#39; = min-x

现在让我们证明x

的范围

我们假设(z-min)%5 >= 3 and (z-min')%5 == 0

所以(z-min')%5 = (z-min+x)%5 = ((z-min)%5 + x%5)%5 == 0

现在,如果x >= 3,那么(z-min)%5永远不能是&gt; = 3才能生成((z-min)%5 + x%5)%5 == 0

如果x = 2,那么(z-min)%5可以是3;如果x = 1则(z-min)%5可以是4,以满足两个条件:5> (z-min)%5 >= 3 and (z-min')%5==0

因此我们一起展示

  

如果5&gt; (z-min)%5> = 3且(z-min&#39;)%5 == 0,然后F(min&#39;)&lt; F(分钟)   其中min&#39; = min-x,x <= 2

注意一个人总是可以生成数组P,这样f(min&#39;)&lt; f(min),因为你总是可以重复整数,这可以通过这种方法改进,直到它输出那些整数不能的数字。这是因为对于无法改进的元素,它们总是需要一个以上的操作

例如:设P = [2,2,2,10] f(min)= 0 + 3 = 3,f(min-2)= 3 + 2 = 5

这里10是可以改进的元素,而2不能,所以我们可以在数组中添加10个。每个2将使用另外1个操作来到min' = min-2,而每个10将保存1个操作以获得min'。因此,我们只需添加更多10,直到数字(补偿)&#34;浪费&#34; 2:

P = [2,2,2,10,10,10,10,10],则f(min)= 0 + 15 = 15,f(min-2)= 3 + 10 = 13

或只是

P = [2,10,10],f(min)= 6,f(min-2)= 5

(TL的结尾; DR部分!)

<强> EDITED

OMG在HACKERRANK上的测试案例很弱!

故事是我今天早上到办公室时,我一直在想这个问题,并且认为我的代码可能有问题(获得了ACed!)

&#13;
&#13;
#include <cmath>
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;

int T, n, a[10005], m = 1<<28;

int f(int m){
    m = max(0, m);
    int cnt = 0;
    for(int i=0; i<n;i++){
        cnt += (a[i]-m)/5 + (a[i]-m)%5/2 + (a[i]-m)%5%2;
    }
    return cnt;
}

int main() {
    cin >> T;
    while(T--){
        m = 1<<28;
        cin >> n;
        for(int i=0; i<n;i++) cin >> a[i], m = min(m,a[i]);

        cout <<  min(min(f(m), f(m-1)),f(m-2)) << endl;
    }
    return 0;
}
&#13;
&#13;
&#13;

你能看到问题吗?

问题是m = max(0, m);

确保min-x必须至少为0,但等等,我上面的证据没有说明min-x的范围!它确实可能是消极的!

请记住,原始问题是关于&#34;添加&#34;,因此目标没有最大值;当我们将问题建模为&#34;减去&#34;时,目标也没有最小值(但我将其设置为0!)

使用上面的代码尝试此测试用例:

&#13;
&#13;
1
3
0 3 3
&#13;
&#13;
&#13;

它强制min-x = 0,所以它给出4作为输出,但答案应为3

(如果我们使用&#34;添加&#34;模型,目标应为10,在[0]上为+5,在[0]上为+5,在[0],[1]上为+5, a [1],a [2])上的+2

所以当我删除行m = max(0, m);时,所有内容终于正确(我认为......),它允许min-x得到否定并将3作为正确输出,当然还有新代码得到ACed ......