【问题标题】:find minimum number of moves to make all elements of array equal to 0找到使数组的所有元素都等于 0 的最小移动次数
【发布时间】:2019-02-27 01:36:09
【问题描述】:

我有一个数组 A = {-8,-5,0,-3,8,8,2,-2},我想计算使用数组元素制作数组 0 的所有元素所需的最小移动次数仅,给定以下条件-->

1. 索引 x 处的元素可以直接移动到 x+1,x+2 一次移动中的位置或 x-1、x-2 位置,之后移动计数 将增加。

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

例如在数组中,最小移动将是 31:

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

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

我尝试用 C++ 编写代码,但力求得到最佳解决方案,也无法涵盖所有​​场景。

下面是我的代码,但不在工作状态

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;
}

【问题讨论】:

  • 你能告诉我们你的代码吗..
  • 添加了我目前正在处理的代码
  • 我在问题陈述中没有看到 - 什么操作将元素 values 更改为 0?
  • 需要将值从值大于0的元素移动到值小于0的元素。使两者都变为0..参见上面有问题的示例

标签: algorithm data-structures


【解决方案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)

【讨论】:

  • 上面的代码没有给出输入solve({-1,-1,0,1,1})的最佳解决方案,因为在这个输入中,如果索引3处的1移动到索引1,那么它将需要1 次移动,索引 4 处的 1 移动到索引 0 然后需要 2 次移动,因为超过 2 次从 4 移动到 0 索引。所以最佳解决方案应该给出输出 3,但上面的解决方案给出输出 4
  • 呃,我的错!错过了可能的情况。我已经用新的解决方案更新了我的答案。请让我知道这是否适合您^.^
  • 很高兴听到它对您有用 :) 如果它确实回答了您的问题,您是否也可以接受它? ^_^
  • 我刚刚意识到我把条件搞砸了,又修改了一次。希望现在一切正常。
猜你喜欢
  • 1970-01-01
  • 2019-09-11
  • 1970-01-01
  • 2022-08-24
  • 2017-09-21
  • 1970-01-01
  • 1970-01-01
  • 2012-12-21
  • 2021-08-29
相关资源
最近更新 更多