【问题标题】:how to make the sequence a non-decreasing sequence with the minimum number of steps?如何使序列成为具有最少步数的非递减序列?
【发布时间】:2011-08-13 13:29:19
【问题描述】:

这是problem 声明

给定一个由 N 个整数组成的序列。在每一步中,允许将任何数字的值增加 1 或减少 1。游戏的目标是使序列在最小步数的情况下不递减

例如,给定

3 2 -1 2 11

可以在 4 步内使该序列成为非递减序列(将 3 减 1 并将 -1 增 3)。

 (-1) (0) (+3) (0) (0)

序列会变成

2 2 2 2 11

我该如何解决这个问题?

【问题讨论】:

  • 最小步数是什么意思
  • @Avinash,它不是最小的步数,而是最小的步数。在 3 2 -1 2 11 的情况下,需要进行 4 次更改,即 (-1) (0) (+3) (0) (0) 对应于每个整数。

标签: algorithm sorting dynamic-programming


【解决方案1】:

我提供了 C# 中的工作代码。它可以轻松移植到您选择的语言。时间复杂度约为 n2。如果 count 大于 minimumValue,可以在 GenerateSequenceForEveryIndex() 方法中进行优化。


using System;
using System.Collections.Generic;

namespace ConsoleApplication2
{
    class Program
    {
        static void Main(string[] args)
        {
            Sequence seq = new Sequence();
            seq.GenerateSequenceForEveryIndex();
            Console.ReadLine();
        }

    }

    class Sequence
    {
        int count;
        public Sequence()
        {
            // Get Number of inputs
            Console.WriteLine("Number of values? ");
            this.count = int.Parse(Console.ReadLine());
            Console.WriteLine("Enter input values followed by RETURN/ENTER");
            GetInputSequence();
        }

        List<int> inputSequence = new List<int>();
        private void GetInputSequence()
        {
            for (int index = 0; index < count; index++)
                inputSequence.Add(int.Parse(Console.ReadLine()));
        }

        internal void GenerateSequenceForEveryIndex()
        {
            int minimumValue = 0;
            for (int index = 0; index < count; index++)
            { 
                // Get output sequence for every index
                // You can make a decision to get the minimum of the moves
                int newValue = GenerateSequenceForCurrentIndex(index);
                if (minimumValue == 0 || minimumValue > newValue) minimumValue = newValue;
                Console.WriteLine("Number of moves: " + newValue);
                Console.WriteLine();
            }
            Console.WriteLine("Minimum number of moves: " + minimumValue);
        }

        private int GenerateSequenceForCurrentIndex(int index)
        {
            int numberOfMoves = 0;
            int[] newOutputSequence = new int[count];
            int[] differenceSequence = new int[count];
            this.inputSequence.CopyTo(newOutputSequence);
            for (int ind = 0; ind < count; ind++)
            {
                if (ind == index) continue;
                differenceSequence[ind] = (ind == 0 ? newOutputSequence[index] : newOutputSequence[ind - 1])
                    - newOutputSequence[ind];

                // If sorted as non-decreasing, continue
                if (ind > index && differenceSequence[ind] < 0) continue;

                numberOfMoves += Math.Abs(differenceSequence[ind]);
                newOutputSequence[ind] += differenceSequence[ind];

            }
            DisplaySequence(differenceSequence, "Diff Sequence: ");
            DisplaySequence(newOutputSequence, "New Sequence: ");
            return numberOfMoves;
        }

        private static void DisplaySequence(int[] newOutputSequence, string heading)
        {
            Console.Write(heading);
            for (int i = 0; i < newOutputSequence.Length; i++)
                Console.Write(newOutputSequence[i] + " ");
            Console.WriteLine();
        }
    }
}

算法说明 每个元素值都可以作为一个枢轴值,意味着它左边的值应该等于它自己的值,右边的值应该大于或等于它自己的值。 话虽如此,最多可以有“n”个唯一的非降序序列。 现在算法获取每个值(参见 GenerateSequenceForEveryIndex 方法)并生成新的非降序序列。

在 GenerateSequenceForCurrentIndex() 中,确保 index 左侧的值等于 array[index]。我们不必担心小于,因为不同的序列已经处理了这一点(当索引

最后,DisplaySequence() 只是显示序列中的值。

【讨论】:

  • 我已经提供了解释。如果它解决了您的问题,请将其标记为已回答。
  • 为什么它是最小的?如果答案不包含最优性证明,则 IMO 不应接受任何答案。
  • @Alexandre,在 GenerateSequenceForEveryIndex() 方法中进行检查以确保选择最小值。循环确保生成所有可能的序列。
【解决方案2】:

问题表明您应该争取最少的更改次数。 假设最后一个数字是-1000000。 如果您按顺序运行序列,您最终将不得不将 1000002 添加到最后一个元素以获得非递减序列,但该解决方案将无法满足使用最小步数的要求。 因此,遍历序列一次,记录元素之间的差异可能是一个好主意。希望你能赶上我的漂移。 (我的写作不像我自己的想法那样清晰:-)

【讨论】:

    【解决方案3】:
    #include <stdio.h>
    #include <stdlib.h>
    
    int get_destination( int numbers[], int size ) {
        int i,j;
        int destination = 0;
        int swap_done = 0;
        for ( i = 0; i < size - 1; i++) {
            for (j = 0; j < size - 1; j++) {
                if ( numbers[j] > numbers[j + 1]){
                    destination = j + 1;
                    swap_done = 1;
                }
            }
            if ( swap_done ) {
                    break;
            }
        }
        return destination;
    }
    int main( int argc, char **argv ) {
        #define SIZE 5
        //int numbers[SIZE]= {3, 2, -1, 2, 11};
        //int numbers[SIZE]= {1,2,3,4,5};
        int numbers[SIZE]= {2, 1, 1, 1, 1};
        int answer = 0;
        int dest = get_destination( numbers, SIZE);
        if ( dest ) {
            for ( int i = 0; i < SIZE - 1; i++) {
                answer = answer + abs( abs(numbers[i]) - abs(numbers[dest]));
            }
        }
        printf ( "ANSWER = %d\n", answer );
        return 0;
    }
    

    如果您查看冒泡排序,在外循环的第一遍中,它将元素放在正确的位置,我正在尝试使用该概念。一旦你找到了第一遍的交换位置,将它作为你的参考,并根据该元素调整序列中的所有元素。

    【讨论】:

    • 请回答你的算法。编码对我来说并不重要。无论如何,为您的支持+1
    • 对于序列 {3, 2, -1, 11, 11},您的算法给出了答案 13。它应该是 4。
    【解决方案4】:

    解决方案可以在 - http://codeforces.com/blog/entry/364

    上面写着-

    请注意,存在一个非递减序列,它可以从给定序列中使用最少的移动次数获得,其中所有元素都等于初始序列中的某个元素(即仅由来自初始序列)。

    证明——

    假设没有最优序列,其中每个元素都等于初始序列中的某个元素。然后有一个元素 i 不等于 {ai} 的任何元素。如果编号为 i-1 和 i+1 的元素不等于元素 i,那么我们可以将其移近 ai,答案将减少。所以有一个相等元素的块,它们都不等于初始序列的任何元素。请注意,我们可以将所有块增加 1 或将其减少 1,并且其中一个操作不会增加答案,因此我们可以向上或向下移动该块,直到其所有元素都等于初始序列中的某个元素。

    算法 -

    假设 {ai} 是初始序列,{bi} 是相同的序列,但其中所有元素都是不同的,并且它们从小到大排序。令 f(i,j) 为获得前 i 个元素不递减且第 i 个元素至多为 bj 的序列所需的最小移动次数。在这种情况下,问题的答案将等于 f(n,k),其中 n 是 {ai} 的长度,k 是 {bi} 的长度。我们将使用以下递归计算 f(i,j):

    f(1,1)=|a1-b1|
    f(1,j)=min{|a1-bj|,f(1,j-1)},  j>1
    f(i,1)=|ai-b1|+f(i-1,1),  i>1
    f(i,j)=min{f(i,j-1),f(i-1,j)+|ai-bj|},  i>1, j>1
    

    复杂度为 O(N2)。为避免内存限制,应注意计算 f(i,) 您只需要知道 f(i-1,) 和已计算的第 i 行的部分。

    【讨论】:

      【解决方案5】:

      你必须找到一个序列

      1. 积分
      2. 非递减
      3. 尽可能接近原始L^1范数

      这是一个约束条件下的凸整数优化问题,似乎很难以最优方式解决。

      【讨论】:

        【解决方案6】:

        我有以下想法:

        1. 构建非递减序列组(在您的示例中 {3} {2} {-1 2 11})
        2. 合并两个组,这样可以将组的数量减少一到两个。
        3. 如果只有一组,则找到非递减解。 如果没有,请返回第 2 步。

        合并:合并两个组总是有两种可能,调整 左组或调整右组。我将在示例中展示这一点, 这个想法应该很清楚。

        调整正确的组:

           {2} {-1 2 11} --> {2} {2 2 11}
           {2} {-1 0 1}  --> {2} {2 2 2}
        

        调整左组:

           {3}   {2} --> {2}   {2}
           {2 3} {1} --> {1 1} {1}
        

        因为总有两种方法可以走(向右调整/向左调整组) 您可以使用回溯算法中的步骤(记住最好的 到目前为止找到的解决方案)。

        演示:

        {3} {2} {-1 2 11}
        adjust left group --> {2 2} {-1 2 11}
        adjust left group --> {-1 -1 -1 2 11}
        

        解决方案:

        {-1 -1 -1  2 11} (adjust left, adjust left)   --> score 7
        { 2  2  2  2 11} (adjust left, adjust right)  --> score 4 (best)
        {-1 -1 -1  2 11} (adjust right, adjust left)  --> score 7
        { 3  3  3  3 11} (adjust right, adjust right) --> score 6
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2016-04-11
          • 1970-01-01
          • 1970-01-01
          • 2018-03-17
          • 2014-03-10
          • 2012-09-09
          • 1970-01-01
          相关资源
          最近更新 更多