这是一个来自编程竞赛的问题(已经结束)。我正在努力解决这个问题,但找不到一个健康的方法来解决这个问题。
问题如下:
IIIT Allahabad将于10月1日至5日庆祝其年度Techno-Cultural Fiesta Effervescence MM12。厨师同意为这个节日提供糖果。厨师准备了N盒糖果,编号为1到N(每个数字恰好出现一次)。厨师非常关注盒子的安排。他希望盒子按特定顺序排列,但不幸的是厨师很忙。他已经要求你为他重新安排盒子。根据框的当前顺序,您必须按指定的顺序重新排列框。但是有一个限制。您只能交换两个相邻的盒子以达到所需的顺序。输出,所需的相邻交换的最小数量。
输入
第一行输入包含单个整数T,测试用例数。每个测试用例包含3行,第一行包含单个整数N,数量为框。接下来的2行每行包含N个数字,第一行是给定的框顺序,第二行是所需的顺序。
输出
对于每个测试用例,输出一个整数'K',即所需的最小相邻交换数。 约束:
1<=T<=10
1<=N<=10^5
实施例
输入:
4
3
1 2 3
3 1 2
3
1 2 3
3 2 1
5
3 4 5 2 1
4 1 5 2 3
4
1 2 3 4
2 3 4 1
输出:
2
3
6
3
我对这个问题几乎一无所知。有人可以解释问题背后的逻辑!!
答案 0 :(得分:6)
这个问题是一个非常“经典”的竞争性编程问题,它正在计算数组中的反转。反转被定义为一对(i,j),其中i <1。 j和A [i]> A [j]的。
最常见的版本,其中包含任意数字的数组,并且要求您计算反转次数,具有O(n log n) solution by modifying merge sort algorithm。
更受限制的版本^,其中数组中最大值上有合理的上限(注意这不是数组的长度),可以在O(n)中求解log m),其中m是数组中的最大值。这里的要点是你必须编写的代码量远远少于合并排序方法。
问题中的问题是计算交换次数以将数组排序到某个顺序,这可以重建为计算交换次数以按升序对数组进行排序,并将其归结为计算数量倒置。为什么反转次数?因为每次交换2个相邻元素时最多只能解决一次反转。
您需要创建一个数组,该数组描述相对于最终设置的框的当前位置。然后算法可以开始:
构造一个长度为m的Fenwick Tree(二叉索引树)(对于问题中的问题,m = n)。
我们将使用Fenwick树来帮助我们计算数组中大于当前元素的前面元素的数量。我们将保持到目前为止遇到的数字的频率,并使用Fenwick树范围求和查询来获得小于当前元素的元素数量(并导出大于当前元素的元素数量)。
循环遍历数组的n个元素:
在(*)步骤中累积的反转计数。
^问题清楚地表明元素是唯一的,因此上面的算法将起作用。我只是不确定唯一性是否是必要条件,或者可以修改算法以适应存在重复元素的情况。
答案 1 :(得分:4)
将源列表减少为(1,2,...,N)的排列。 (通过将目标的反转应用于源)
然后计算反转次数。
即
vector<int> source = ...;
vector<int> target = ...;
vector<int> inv(N)
for (int i = 0; i < N; i++)
inv[target[i]] = i;
vector<int> perm(N);
for (int i = 0; i < N; i++)
perm[i] = source[inv[i]];
然后使用标准算法计算烫发的反转。
答案 2 :(得分:2)
假设所需的顺序是数字的排序顺序,问题就减少到找到数组中的反转次数。
如果pair (i,j)
和i < j
,array[i] > array[j]
被认为是倒置。这是因为相邻元素之间的每次(最佳)交换减少了正好1
的反转次数。您可以通过与合并排序非常相似的分而治之算法找到O(n log n)
中的反转次数。这是一个很好的解释with C code。
编辑证明反转次数等于最佳互换次数:
让i
成为array
中的任何位置。交换array[i]
和array[i+1]
会将反转次数减少最多1.因此,所需的互换次数至少等于反转次数。另一方面,如果未对array
进行排序,我们总能找到一对(i, i+1)
,以便array[i] > array[i+1]
(即(i,j)
是反转),并减少反转次数1,通过array[i]
与array[i+1]
交换。因此,反转次数等于最小交换次数。
答案 3 :(得分:0)
该问题可被视为反转计数问题如下:
由于数字的优先级是按照我们应该排序的顺序给出的。
考虑优先级并将其替换为数字
e.g:
3 4 5 2 1
4 1 5 2 3
在上面的测试案例中,我们可以观察到4被分配了优先级1,1被分配了优先级2,5被分配了优先级3,依此类推。 那么为什么不用这些优先级替换原始列表中的数字
即。转换原始列表
(3 4 5 2 1) to (5 1 3 4 2)
(只是用上面讨论的各自的优先级替换数字)
现在我们的列表已转换为
5 1 3 4 2
我们应该按升序排序。
现在我们只允许相邻的互换,即与冒泡排序有些相关。
冒泡排序所需的掉期数量,等于每个元素右侧元素数量的总和,小于当前元素。
例如:在列表中
5 1 3 4 2
5右侧有4个小于5的元素。
1在右侧有0个小于1的元素。
3右侧有1个小于3的元素。
4右侧有1个小于1的元素。
2在右侧有0个小于2的元素。
现在最后的答案是(4 + 0 + 1 + 1 + 0)= 6.
现在可以使用此处讨论的反转计数来计算上述过程 http://www.geeksforgeeks.org/archives/3968。
注意:我获得的答案非常有用,只是详细描述了整个事情。 谢谢
答案 4 :(得分:-1)
我不能用数学证明这一点,但是在4/4的测试用例中,你可以通过从最左边开始将盒子放在正确的位置(也可以用最右边的方式)并向右移动来获得最小的交换。即。
3 4 5 2 1 //First get the 4 in the right place
4 3 5 2 1 //Done. Now get the 1 in the right place
4 3 5 1 2
4 3 1 5 2
4 1 3 5 2 //Done. Now the 5
4 1 5 3 2 //Done. Now the 2
4 1 5 2 3 //All done.
所以这个算法看起来会给你任何给定输入的最小值。最坏的情况通常看起来像是逆转,需要N *(N-1)/ 2掉期(见例2)。