找到使数组的所有元素等于0的最小移动次数

时间:2018-09-23 07:49:09

标签: algorithm data-structures

我有一个数组A = {-8,-5,0,-3,8,8,2,-2},我想计算最小移动数需要使用数组元素使数组0的所有元素仅在满足以下条件的情况下->

1。索引为x的元素可以直接移动到x + 1,x + 2     一次移动中的x或x-1,x-2位置     将增加。

  1. 在数组的起始索引(即0)之前和结束索引(即数组的长度)之后,不能移动任何元素。

例如高于最小移动的数组中的值为31:

  1. 索引16的所有8个元素可以总共16步移动到索引0 (因为所有8个元素都需要移动2步)。移动:16。
  2. 索引3中的3个元素可以3步移动到索引3(3个元素各移动1个步),索引5中的其余5个元素可以移动到索引2 每10步(5个元素每个需要2步,所以总共10步)。 动作= 16 + 3 + 10 = 29。
  3. 索引6中的
  4. 2个元素在2中移至索引7 moves(每个移动1个)移动= 29 + 2 = 31。

以输入数组{-1,-1,0,1,1}的另一个示例为例,最优解给出答案3如下-> 索引3中的1从1中移动到索引1,然后索引4中的1在2中移动到索引0,因此总移动将为3。

我尝试用C ++编写代码,但dint获得了最佳解决方案,也无法涵盖所有​​情况。

以下是我的代码,但未处于工作状态

int solution1(vector < int > & c) {

  int alen = c.size();
  if (alen == 0) return -1;

  int move = 0;
  int moved = 0;
  for (int j = 0; j < alen; ++j) {
    if (c[j] < 0) {
      for (int k = j + 1; k < alen; ++k) {
        moved = 0;
        if (c[k] > 0) {
          c[j] = 0 - c[j];
          if (c[j] <= c[k]) {
            c[k] = c[k] - c[j];
            moved = c[j];
            c[j] = 0;
          } else {
            c[j] = c[k] - c[j];
            moved = c[k];
            c[k] = 0;
          }
          if (k - j >= 2) {
            if ((k - j) % 2)
              move += ((k - j + 1) / 2) * moved;
            else
              move += ((k - j) / 2) * moved;
          } else {
            move += moved;
          }
          if (c[j] == 0) break;
        }
      }
    } else if (c[j] > 0) {
      for (int kk = j + 1; kk < alen; ++kk) {
        moved = 0;
        if (c[kk] < 0) {
          c[kk] = 0 - c[kk];
          if (c[j] <= c[kk]) {
            c[kk] = c[j] - c[kk];
            moved = c[j];
            c[j] = 0;
          } else {
            c[j] = c[j] - c[kk];
            moved = c[kk];
            c[kk] = 0;
          }
          if (kk - j >= 2) {
            move += ((kk - j) / 2) * moved;
          } else {
            move += moved;
          }
          if (c[j] == 0) break;

        }
      }
    }

  }
  if (move > 0) return move;
  else return -1;
}

1 个答案:

答案 0 :(得分:1)

给定的问题需要建设性的解决方案。由于移动范围扩展到(x-2,x + 2),因此我们维护着大小为2的overhead数组,当我们从出发时,该数组保持了元素移动的成本从i (i +1) th 位置,以获取偶数和奇数索引。我们从左到右迭代给定的数组,并计算将所有剩余元素移到索引 i 左边的成本。可以使用开销数组(请参见下面的代码)来计算这种成本。如果在任何步骤中都有可能用正整数抵消一些负整数,那么我们首先选择那些元素,如果他从 i 转到( i + 1),这是我们进行中和过程的下一步。

观察点是,如果我们继续从左到右移动索引 x 处的元素,只会增加点(x + 1),(x + 3),(x + 5), ...等。这是相同的运行代码:https://ideone.com/TFunNG

int solve(vector<int> v) {
    vector<int> overhead(2,0);
    int num_of_moves = 0, sum = 0;
    for(int i = 0; i < v.size(); i++) {
        num_of_moves += overhead[i % 2];
        int left = abs(v[i]);
        if((sum > 0 && v[i] < 0) || (sum < 0 && v[i] > 0)) {
            int used = min(abs(sum), abs(v[i]));
            int diff = min(overhead[(i + 1) % 2], used);
            overhead[(i + 1) % 2] -= diff;
            overhead[i % 2] -= min(overhead[i % 2], (used - diff));
            left -= used;
        }
        sum += v[i];
        overhead[(i + 1) % 2] += abs(left);
    }

    assert(sum == 0);
    return num_of_moves;
}

该解决方案的总体运行时复杂度为 O(n)