简体   繁体   English

使用简单的数组对数字进行堆叠?

[英]Using simple arrays to sort numbers by stacking them?

This is a homework question (sorry, I know these are frowned upon), but neither I nor the teacher actually knows how to solve it efficiently, so I wanted to put it up here to see if the wonderful brains on SO could help us out. 这是一个家庭作业问题(对不起,我知道这些问题被忽略了),但是我和老师都不知道如何有效地解决它,所以我想把它放在这里,看看SO的出色人才是否可以帮助我们。

An array of unspecified size is given, containing random numbers. 给出了一个未指定大小的数组,其中包含随机数。 It must be sorted into increasing order. 必须按升序排序。 Each element can be either moved to an adjacent empty space, or moved on top of an adjacent larger element. 每个元素可以移动到相邻的空白空间,也可以移动到相邻的较大元素的顶部。 I need to write a method that returns the minimum number of moves needed to sort the given array. 我需要编写一个方法,该方法返回对给定数组进行排序所需的最小移动量。

The question has been labeled 'optional', since the teacher realized the problem was far too difficult, but I'm curious how it might be solved. 这个问题被标记为“可选”,因为老师意识到这个问题太难了,但是我很好奇如何解决。 Any suggestions for arrays of any size (it can be for arrays of length 3 for all I care) are appreciated. 对于任何大小的数组的任何建议(就我而言,长度可能为3的数组)都值得赞赏。

EDIT: Thanks for pointing out that this was unclear. 编辑:感谢您指出这不清楚。 I'm using the array to represent a hypothetical real world situation. 我正在使用数组表示假设的现实世界情况。 Let's use the example of coins: they are all laid out on a table in a row, and there are only a specified number of 'spaces' they can be put in. But they can be put on top of adjacent larger coins, or slide to an adjacent empty space (which has been vacated by a coin that had presumably moved on top of a pile). 让我们以硬币的示例为例:它们都连续放置在一张桌子上,并且只能放入指定数量的“空格”。但是可以将它们放置在相邻的较大硬币的顶部,或者滑动到相邻的空白空间(该空白空间已被可能在桩顶移动的硬币腾空了)。

I decided to examine the problem with a few assumptions/changes, because it made it a more interesting problem to me: 我决定在做一些假设/更改后再研究这个问题,因为这使它成为我一个更有趣的问题:

1) You can move elements left or right from any part of a pile. 1)您可以从桩的任何部分向左或向右移动元素。

2) You can stack an element onto a pile no matter if it's bigger, smaller or the same size. 2)您可以将元素堆叠到桩上,无论它是大,小还是相同大小。

3) The array is considered sorted as long as you never encounter a bigger number before a smaller number no matter how you go through stacks. 3)只要您不经历较大的数目就不会在较小的数目之前遇到较大的数目,就可以认为该数组已排序,无论您如何遍历堆栈。 So _ 11 2 3 is sorted but _ _ 12 3 is not because you could interpret the 2 as being before the 1. 所以_ 11 2 3被排序了,但是_ _ 12 3不是因为您可以将2解释为在1之前。

This leads to a very interesting problem, in spite of this axiom: 尽管有这个公理,这仍然导致了一个非常有趣的问题:

Axiom A: The order in which you make moves is irrelevant, and can be re-arranged in any way to still achieve the same final result. 公理-答:您移动的顺序是无关紧要的,可以以任何方式重新安排,以仍然达到相同的最终结果。

Axiom Ab: If the array has no repeats in it, then simply move every element towards its final position. 公理Ab:如果数组中没有重复,则只需将每个元素移到其最终位置即可。

In particular, I developed a strategy hoping that you could solve it with only local examination and no recursiveness/backtracking, but I've proven that this is fruitless and will show it later. 特别是,我制定了一项策略,希望您仅通过本地检查就可以解决此问题,而无需进行递归/回溯,但是我已经证明这是徒劳的,以后再介绍。

My strategy is: 我的策略是:

1) Proceed from left to right looking for pairs that are flipped the wrong way (a higher number before a lower number). 1)从左向右继续,寻找对方向错误的对(数字越大,数字越小)。

2a) When you find one, if there is an empty spot or a stack that the right hand value could immediately fill, move it left until it does fill it. 2a)找到一个空白点或堆栈时,如果右边的值可以立即填满,请将其向左移动,直到填满为止。

2b) Else, move the left value right one. 2b)否则,将左值右移一个。 This creates a situation where you have a stack of indifferent numbers - first, compare the value you moved right to the value on its new right according to the logic of 1) before comparing downwards. 这会造成一堆无关紧要的数字的情况-首先,在向下比较之前,根据1)的逻辑将右移的值与新右移的值进行比较。

2bii) Treat a downwards comparison the same way as a pair comparison - move the lower value left if it can fit an empty spot or stack, else move the higher value right and continue. 2bii)与对比较一样对待向下比较-如果较低的值可以容纳空白点或堆栈,则将其左移,否则将较高的值向右移动并继续。

Examples: 例子:

1231 -> we shift 1b left because it will fit onto a stack. 1231->我们将1b左移,因为它将适合堆栈。 11 2 3 _ 11 2 3 _

1321 -> we shift 3 right because 2 will not fit into an empty spot/onto a stack. 1321->我们将3右移,因为2不能容纳在一个空位/堆栈上。 we shift 1b left twice because it will fit into an empty spot/fit onto a stack, then we shift 3 right because 2 will not fit into an empty spot/onto a stack. 我们将1b左移两次,因为它将适合一个空位/适合堆栈,然后我们将3向右移,因为2将不适合一个空位/不适合堆栈。 1 1 2 3 1 1 2 3

1132 -> we shift 3 right as 2 can't go left. 1132->我们将3右移,因为2不能左移。 we shift 2 left because it will fit in an empty spot. 我们将2左移,因为它将适合一个空白点。 1 1 2 3 1 1 2 3

2311 -> we shift 3 right as 1a can't go left. 2311->我们将3右移,因为1a不能左移。 we shift 1b left twice because it will fit in an empty spot. 我们将1b左移两次,因为它将适合一个空白点。 we shift 1a left because it will stack. 我们将1a左移,因为它将堆叠。 we shift 2 right because 1a1b can't go left. 我们将2右移,因为1a1b不能左移。 we shift 1a2b left as it will fill an empty spot. 我们将1a2b左移,因为它将填充一个空白点。 11 2 3 _ 11 2 3 _

However, we run into a problem with these two starting arrays: 但是,我们遇到了以下两个起始数组的问题:

23411 10 moves optimal, 2r 3r 4r 1al*3 1bl*4 to make 11 2 3 4 _. 23411 10移动最佳,2r 3r 4r 1al * 3 1bl * 4使11 2 3 4 _。

23111 9 moves optimal, 2r*3 3r*3 1bl 1cl*2 to make _ _ 111 2 3 - the opposite of the 23411 strategy! 23111 9移动最佳,2r * 3 3r * 3 1bl 1cl * 2使_ _ 111​​ 2 3-与23411策略相反! We move the 1s less and the 23 more because there are more 1s and so we save moves moving them as little as possible. 我们将1移少,将23移多,因为存在更多的1,因此,我们保存了尽可能少地移动它们的动作。

Which shows that we can't JUST do a simple local comparison to solve this new problem. 这表明我们不能仅仅做一个简单的局部比较来解决这个新问题。

I'm still thinking about this problem, it seems non-trivial in an intriguing way, and I hope some of you enjoy contemplating this with me :) 我仍在考虑这个问题,这似乎很有趣,我希望你们中的一些人喜欢和我一起考虑这个问题:)

I assume: 我假设:

  • "sorted" means there is a single stack left “已排序”表示仅剩一个堆栈
  • we can only move a stack onto another stack if the largest number in the source stack is smaller than the smallest number in the destination stack (or equivalently: stacks must be sorted with smaller numbers on top, and moving a stack onto another moves the entire stack on top of the other) 我们只有在源堆栈中的最大数目小于目标堆栈中的最小数目时(或等效地:堆栈必须在顶部以较小的数目进行排序,然后将堆栈移动到另一个堆栈中,才能将堆栈移动到另一个堆栈中)堆叠在另一个之上

Then, there is obviosly no solution if the array contains a number more than once. 然后,如果数组包含一个以上的数字,则没有解决方案。 Also, the magnitude of the numbers doesn't matter, only their rank does. 同样,数字的大小无关紧要,只有排名重要。 Without loss of generality, we can therefore assume that the array contains the numbers 1..n in arbitrary order. 因此,在不失一般性的前提下,我们可以假定数组以任意顺序包含数字1..n。 Also, to determine the possible moves, only the top of bottom of the stacks matter. 同样,为了确定可能的移动,仅堆叠底部的顶部很重要。 It is therefore sufficient to store: 因此,足以存储:

int[] bottom;
int[] top;

Since we can not take stacks apart, we may only move stack i onto stack j if bottom[i] + 1 == top[j] , or we'll end up in an unsolvable state. 由于无法将堆栈拆开,因此只有在bottom[i] + 1 == top[j] ,才可以将堆栈i移动到堆栈j上,否则我们将陷入不可解决的状态。 If however, we are in a game state where such a move is possible, it is optimal to perform it immediately, because eventually we'll have to combine these stacks, and moving an individual stack around is cheaper than moving two stacks around. 但是,如果我们处于可以进行此类移动的游戏状态,则最好立即执行此操作,因为最终我们必须将这些堆栈组合在一起,并且移动单个堆栈要比移动两个堆栈便宜。

The only degree of freedom therefore is how to move the stacks into position with the least number of moves. 因此,唯一的自由度是如何以最少的移动次数将堆栈移动到适当的位置。 At this time, I don't see an obvious greedy algorithm for that, so finding the optimal solution may require encoding the positions of the game into a graph, and apply a shortest path algorithm to that graph to find the shortest sequences of moves. 目前,我还没有看到一个明显的贪婪算法,因此要找到最佳解决方案,可能需要将游戏的位置编码为图形,然后将最短路径算法应用于该图形以找到最短的移动顺序。

EDIT: Given that everyone seems to be solving a different problem, I'll state the problem I'm solving (which I believe to be the correct one (don't we all?)): (using disks to hopefully make things easier to understand) 编辑:鉴于每个人似乎都在解决一个不同的问题,我将陈述我正在解决的问题(我相信这是正确的(不是所有人吗?)):(希望使用磁盘使事情变得更容易了解)

Given n piles, each containing exactly 1 disk each, order these disks in increasing order of size. 给定n个堆,每个堆分别恰好包含1个磁盘,请按大小递增的顺序对这些磁盘进行排序。 The end result must have each pile containing 1 disk each. 最终结果必须使每个堆每个包含1个磁盘。 The only allowed operation is to move a single disk from the top of one pile to the top of an adjacent pile, subject to the constraint that no disk may be placed on top of a smaller disk. 唯一允许的操作是将单个磁盘从一个堆的顶部移动到相邻堆的顶部,但要遵守以下条件:不得在较小的磁盘上放置任何磁盘。 Moving a disk to an empty pile or moving the last disk from a pile is allowed. 允许将磁盘移动到空堆或将最后一个磁盘从堆移动。 There are always n piles, thus: (1) New piles may not be created, so a disk may not be moved outside the bounds of the original sequence. 总会有n个堆,因此:(1)可能不会创建新的堆,因此可能不会将磁盘移到原始序列的边界之外。 (2) Empty piles remain, so if the adjacent position is empty, the disk may not be moved over that position without first being moved onto that position. (2)保留有空堆,因此,如果相邻位置为空,则在未先将磁盘移动到该位置的情况下,不得将其移到该位置上。

Note: 注意:

A disk with a diameter of x = a number x. 直径为x的磁盘=数字x。

This may not be the most efficient solution, but it should work and may give someone something to work off of. 这可能不是最有效的解决方案,但是它应该可以工作,并且可以给某人一些帮助。

It's a purely iterative process - after every step we end with all stacks having size 1; 这是一个纯粹的迭代过程-在每一步之后,我们以所有大小为1的堆栈结束; this may be a fundamental inefficiency with this approach. 这可能是这种方法的根本低效之处。

Solution: 解:

I'll use 1, 2 and 5 to illustrate the below, but this is just to indicate size ordering, it holds the same for any other numbers with the same ordering. 我将使用1、2和5来说明以下内容,但这只是为了指示大小顺序,对于具有相同顺序的任何其他数字,它都具有相同的含义。

  • Repeat until sorted: 重复直到排序:
    • Find the biggest element not already in the correct position ( 5 in this case) 查找尚未位于正确位置的最大元素(在这种情况下为5
      • (Actually it doesn't have to be the biggest, just anything in the below form, but be careful not to move elements past where they should be) (实际上,它不一定是最大的,只要是下面形式的任何东西,但是请注意不要将元素移到应该超出的位置)
    • We have 2 cases: 我们有两种情况:
      • It's at the left-most position, we have 2 cases: 它在最左侧,我们有2种情况:
        • 512... - move 1 right, move 5 right, move 1 2 left, end with 152 512...向右移动1向右移动5 ,向左移动1 2,以152结尾
        • 521... - move 1 2 left, move 2 right, move 1 2 right, move 5 right, move 1 2 left, end with 152 521...向左移动1 2,向右移动2向右移动1 2,向右移动5 ,向左移动1 2,以152结尾
      • It's not at the left-most position, we have 2 cases: 它不在最左边,我们有两种情况:
        • ...251... - move 1 2 left, move 5 right, move 1 right, end with 215 ...251...向左移动1 2,向右移动5向右移动1 ,以215结尾
        • ...152... - move 2 left, move 1 right, move 1 right, move 2 left, end with 251 (after which we do steps from previous case) ...152... -移动2左,移动1右移,上移1右移,上移2左,最终以251 (之后我们做从以前的情况下,步长)

EDIT 2: 编辑2:

A more efficient solution: 更有效的解决方案:

  1. Find the smallest disk not in the right position 查找位置不正确的最小磁盘
  2. Put it on top of the disk to the right 将其放在磁盘右侧的顶部
  3. Shift all disks to the left of that disk 1 position right 将所有磁盘移到该磁盘的左侧1个位置的右侧
  4. Shift the smallest disk all the way to the left (until you encounter a smaller disk which would already be in the right place) 将最小的磁盘一直向左移动(直到遇到一个较小的磁盘,该磁盘已经在正确的位置)

Possible preprocessing step: Sort to a separate list to efficiently find smallest elements 可能的预处理步骤:排序到单独的列表以有效地找到最小的元素

Optimization: If you were going to move a disk to the right past its target position, instead, don't shift the disk on the right to the right in the previous step, but simply put this disk on that disk. 优化:如果要将磁盘移至目标位置的右侧,则不要在上一步中将磁盘从右侧移至右侧,而只需将该磁盘放在该磁盘上即可。 How to do this at the right time efficiently may be a bit complex. 如何在正确的时间高效地执行此操作可能会有些复杂。 It may also be helpful to not perform certain moves to increase efficiency. 不执行某些举动以提高效率也可能会有所帮助。

Example: 例:

52413

// put smallest disk (1) on disk to the right
    1
524_3

// shift disks to the left 1 position right (3 moves - moved 4, then 2, then 5)
    1
_5243

// move 1 all the way left (4 moves)
15243

// same as above for 2

   2
15_43

   2
1_543

12543

When the smallest disk is on the right-most position (as is now the case with 3 ), this is a bit of a problem. 当最小的磁盘位于最右边时(如现在3的情况),这有点问题。 2 ways of resolving it: 2种解决方法:

  • Swap 1 and 2 and put 1 on 2 ( 1 2 positions right, 2 left, 1 2 positions left). 交换12然后将1放在2 (向右1 2个位置,向左2向左1 2个位置)。 Then you'd have an open spot onto which to move 3 . 然后您将有一个空旷的地方可以移动3 Not an option if there's less than 2 smaller elements. 如果少于2个较小的元素,则不是一种选择。 These elements shouldn't be fixed until we've sorted a few more elements, in case we run into the same situation. 在我们对其他一些元素进行排序之前,不应修复这些元素,以防遇到相同的情况。

  • If we had 12453 , we could simply put 4 on 5 to open a slot for 3 (which sort of delays the problem). 如果我们有12453 ,我们可以简单地将4放在5以打开3的插槽(这会延迟问题)。 If the first non-sorted disk ( 5 in this case) is bigger than the second one ( 4 ) we could use some strategy like I described for my previous solution above to move elements to satisfy this condition. 如果第一个未排序的磁盘(在这种情况下为5 )大于第二个未排序的磁盘( 4 ),我们可以使用上面针对我先前的解决方案描述的某些策略来移动元素以满足此条件。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM