【问题标题】:Minimum number of moves required to get a permutation of a int of array?获得数组 int 的排列所需的最少移动次数?
【发布时间】:2014-07-23 12:12:42
【问题描述】:

您有一个d[0] , d[1], d[2] , d[3] ,..,d[n] 序列。在每次移动中,您可以将任何 d[i] 增加 1 或 2 或 5 i:0 到 n 。将序列转换为 [1,2,3,..,n] if it's possible else return -1. 1<=n<=1000 排列所需的最小移动次数是多少?

我的方法是将给定数组按升序排列,而不是通过添加 1 或 2 或 5 来计数。但它在很多情况下都失败了。Some of my classmates did this in exam using this method but they read question wrong so read question carefully .

例如[1,1,3,2,1] 比答案是 4 因为我们可以通过分别添加 0,1,2,2,2 得到 [1,2,5,4,3 ] 所以答案是 4 。

[1,2,3,4,1] => [1,1,2,3,4] 我们将使用排序方法 [0,1,1,1,1] 得到 4 但答案是 2 因为我们可以在 1 中添加 [2+2] 得到 [1,2,3,4,5] 。

类似

[1,2,3,1] =>[1,1,2,3] 到 [1,2,3,4] 需要 3 次转换,但答案是 2,因为通过将 [1+2] 添加到 1我们可以得到 [1,2,3,4]。

另一种方法可以用作i don't have any proof for correctness

Algorithm
    input "n" is number of element , array "a" which contains input element 
    initialize cnt = 0 ;
    initialize boolarray[n] ={0};
    1. for i=0...n  boolarray[a[i]]=1;
    2. put all  element in sorted order whose boolarray[a[i]]=0 for i=0...n
    3. Now make boolarray[a[i]]=1; for i=0..n and count
      how many additions are required  .
    4. return count ;

根据我的说法,这个问题总是会导致 0 或更多,因为任何数字都可以使用 1 、 2 和 5 产生,除非任何 d[i] i=0..n 大于 Inputs 的数量。

How to solve this correctly ? 

欢迎任何回答和建议。

【问题讨论】:

  • 解决方案总是可行的吗?对此的要求是 d[i]
  • 如果没有则返回 -1 。
  • 这是一道作业题吗?
  • 向我们展示您的方法
  • 你能展示一些你的方法失败的案例吗?并告诉我们这些情况下的正确值是多少,以及您是如何知道的。

标签: arrays algorithm int sequence permutation


【解决方案1】:

你的问题可以转换成weighted bipartite matching问题:-

  1. 图的第一部分 p1 是当前数组编号作为节点。
  2. 图表的第二部分 p2 是数字 1 到 n。
  3. p1 的节点到节点 p2 之间存在边,如果我们可以添加 1,2,5 使其成为 p2 中的节点。
  4. 加权二分匹配可以使用匈牙利算法解决

编辑:-

如果您正在评估最小移动次数,则可以使用 unweighted bipartite matching 。您可以使用 hopcroft-karp 算法,它在您的情况下以 O(n^1.5) 运行,作为图中的边数 E = O(n)

【讨论】:

  • 但是复杂度太高了 o(n^3) 。可以使用 sort 解决。再次阅读问题并检查“any d[i]”是否有任何含义
  • @user3805652 如果您在同一个链接中签入,则有一种算法使用斐波那契堆在 O(n^2*logn) 中完成。最大 n 是多少?
  • @user3805652 抱歉,我误读了您的问题,并认为您需要最小化额外附加值的总和,但您必须最小化移动的总数。检查我的编辑
  • @user3805652 是的,我后来意识到了
【解决方案2】:

创建一个数组count,其中包含我们在基本数组中出现特定数字的频率

input    1 1 3 2 1
count    3 1 1 0 0

现在遍历这个数组并计算步数

sum = 0

for i: 1..n
    while count[i] > 1                   // as long as we have spare numbers

        missing = -1                     // find the biggest empty spot which is bigger than the number at i
        for x: n..i+1                    // look for the biggest missing
            if count[x] > 0 continue     // this one is not missing
            missing = x
            break;

        if missing == -1 return -1       // no empty spot found

        sum += calcCost(i, missing)
        count[i]--
        count[missing]++

 return sum    

calcCost 必须是贪心的

【讨论】:

  • 在所有情况下都不选择最大的缺失数字可能是有利的。例如,如果您正在寻找如何生成 10,并且在可用数字中同时获得 5 和 7,您可能必须选择 5,因为这需要 1 步才能达到 10,而 7 需要 2,但是这取决于您以后可以使用 7 的内容。
  • @LasseV.Karlsen 我从左到右运行,而缺失从右到左运行,所以我取最大的缺失和最小的备用数,结果将 5 提升为 10在您的示例中为 7 到 8 或 9
猜你喜欢
  • 1970-01-01
  • 2020-02-12
  • 2012-03-30
  • 1970-01-01
  • 2014-04-21
  • 2017-01-09
  • 1970-01-01
  • 2019-01-18
相关资源
最近更新 更多