交换问题

Published: by Creative Commons Licence

  • Tags:

01序列最少交换次数

现在给定等长且含有相同数量1的两个二进制序列,记作A、B。

我们可以对序列A做如下操作,交换两个相邻的位的值。问最少需要多少次操作,可以将A转换为B。

譬如:

A=0110

B=1001

很显然将第一位和第二位交换,将第三位和第四位交换就可以得到想要的结果,且任意可能的方案都至少要进行两次交换,因此答案是2。

这个问题的解法非常简单,我们记A中1出现的位置从小到大为a1,a2,,ak,B中1出现的位置从小到大为b1,b2,,bk可以证明A中原本位于ai的1会最终被放置在bi

事实上,我们永远不会交换两个相同的值,因此ai+1永远不会交换到a1之前。因此我们可以直接证明a1b1相匹配(这里匹配的意思是A中原本a1处的1最终会移动到b1)。同理可以证明其它1的匹配。

因此答案为:ki=1|aibi|

这个问题可以在树上进行定义。对于一颗树,我们为顶点的初始值赋值为1或0,接下来,每个顶点还有一个目标值。我们可以交换两个之间存在一条边的顶点的值,我们的目的是使得最终树上每个顶点的值和目标值相同,并要求步骤数最少。

很显然,如果目标值中的1和初始值中的1的数目不同(简单说目标值的和和初始值的和不同),那么问题是无解的。下面考虑相同的情况。

对于树中的任意一条边,该边会将树分成两个连通块。我们称连通块的不平衡度为连通块中值的和与目标值的和的差的绝对值。很显然删除边e后,两个连通块的不平衡度是相同的。记f(e)为树失去边e后形成的连通块的不平衡度,称为边两端不平衡度。 很显然式子 eEf(e) 是结果的一个下界。我们可以这样理解这个式子,由于删除e后,两个连通块的不平衡度均为f(e),那么必定至少有f(e)个1从一个连通块中经过边e转移到另外一个连通块中。

下面我们设计一个算法,可以在下界次操作中完成转换。

首先我们从图中删除所有两端不平衡度为0的边,仅保留不平衡度非0的边。假如连通块大小都为1,这意味着没有边存在,即所有顶点的值和目标值是相同的,这时候我们自然可以在下界次(0)操作中完成转换。

利用反证法,假设不存在这样的边e,使得e的两端顶点的值一个为1,一个为0,且为1的顶点所在连通块的值和减去目标值和是正数。任意考虑一个大小非1的连通块。连通块一定是树,因此一定存在度数为1的叶子结点v。叶子结点的值和目标值必定不同,我们不妨设叶子结点的值为0,目标值为1。之后考虑v的父结点u,很显然父结点一定也是0(否则与假设相悖)。利用归纳法我们可以推广证明对于任意高度的树,树中的值必定都是相同的。当然这样的话,就意味着连通块的不平衡度非0,这是不可能的。因此假设不成立,存在这样的一条边,两端顶点值不同且1所在的连通块的值减去目标值和是正数。

我们将上面提到的边两端的顶点的值交换,发现除了e两端不平衡度减少了1以外,其余边的不平衡度都没有发生变化。

而上面的操作最多发生下界次,因此就证明了存在一种方案可以在下界次交换中使得每个顶点的值和目标值是相同的。

置换排序最少交换次数

一道综合题目

问题1:给定1,2,,n的置换序列a1,,an,每一次操作是交换两个相邻的数,问最少需要多少次操作才能将序列排序。

x为序列中的逆序对数目,可以发现我们每次交换都可以且最多仅可以将逆序对数目减少1,只有逆序对数目为0的情况下流程才结束。因此答案就是x

要统计逆序对,可以利用BIT。时间复杂度为O(nlog2n)

问题2:给定1,2,,n的置换序列a1,,an,每一次操作是交换两个不同位置的数,问最少需要多少次操作才能将序列排序。

在置换的角度来看,我们可以发现问题实际上在问我们可以用多少个二元置换将输入置换恢复为标准置换。我们从图的角度来看置换,这时候置换可以表示为若干个环,每个二元置换,如果发生在同一个环中,这个环会被拆分成两个环,如果发生在不同的环中,这两个环会被合并为一个环。而我们的目的是的到n个环,因此至少需要操作次数为nC,其中C表示原来的环数。

问题3:给定1,2,,n的置换序列a1,,an,每一次操作是删除一个数,并将被删除的数插入到任意位置,问最少需要多少次操作才能将序列排序。

可以发现没有被删除的数一定保留原来的顺序,换言之,它们是严格递增子序列,其余数需要一次删除。因此我们要让删除次数最少等价于不被删除的数最多,即求LIS,答案为nLIS

问题4:给定1,2,,n的置换序列a1,,an,每一次操作是删除一个数,并将被删除的数插入序列最前面,问最少需要多少次操作才能将序列排序。

首先每个数最多被删除一次,如果数字m被删除,则m1一定也会被删除一次。因此我们要让被删除的最大数最小,而其余不被删除的数保持原来顺序,因此我们要找到形如i,i+1,,n的最长递增子序列。这个可以O(n)求解。

问题5:给定1,2,,n的置换序列a1,,an,每次操作选择任意个互不相交的下标对,之后对没对下标(i,j),交换aiaj。现在要求用最少的操作次数使得序列有序,给出最少操作次数。

提供一道题目

首先如果置换已经有序,答案为0。否则如果对于所有i都有i=aai成立,那么答案为1,我们直接将这些元素全部交换。否则,答案至少为2。下面我们给出一个算法可以在两次操作解决这个问题。

首先这时候一定至少有一个环长度大于2。设环的长度为m,且环中的元素为c1,,cm。对于任意k0,如果有2+k<mk,则在第一轮交换(2+k,mk)。在第一轮操作后,会发现一定有对于所有i都有i=aai成立,这时候一次简单操作就可以使得整个序列有序。(理解一下二元置换意味着拆环,第一轮我们将环拆分成不超过2长度)。

问题6:给定1,2,,n的置换序列a1,,an,每一次操作是删除一个数,并将被删除的数插入序列最前面或最后面,问最少需要多少次操作才能将序列排序。

如果一个数x被插入到前面,则x1一定也要被操作一次。同理如果一个数x被插入到后面,则x+1一定也会被插入到后面一次。因此真正不动的是一段递增序列a1,,ak,其中ai=a1+i1

可以直接线性算法求解答案,结果为O(n)

问题7:给定一个01序列,要求对其排序。你可以完成若干次下述操作,每次批次选择若干对邻近的10,将其全部替换成01。问至少需要多少次操作才能让整个序列有序。

这个问题和问题1不同,原因是它每次可以批量交换。但是由于是01序列,因此批量交换的规则也简单不少。

我们可以从左到右枚举0的位置,记第i0前面有pi1,至少需要ri轮操作才能将其移动到所有1之前。

对于序列前面的0,我们可以将其删除,不影响结果。可以发现对于第i0,由于其前面有pi1,而每一轮操作它最多越过一个1,因此至少需要操作pi轮,但是这里还需要分两种情况讨论,如果在抵达之前接触到了第i10,由于不可能越过它,因此我们的操作次数应该至少为ri1+1,没有遇到,那么操作次数仅受前面1的数目所限制。因此第i0抵达所有1前操作次数为max(ri1+1,pi)

推荐一道题目:SRM783 CardboardBoxes。

问题8:给定一个长度为n的置换,允许每次交换两个相邻的元素,要求你用最少的次数将其整理为一个前面部分递增后面部分递减的序列,允许前面部分或后面部分为空。其中1n106

提供一道题目

我们可以将后面的数x修改为x,这样问题就变成了标准的使序列递增的问题。那么现在我们首先需要选择一个子集,将子集中的元素全部修改。如何确定这个子集成为了唯一的问题。

当我们考虑转换一个元素时,我们定义x为元素x的偏移,那么每个逆序对(u,v)的费用,我们将它赋予给偏移较大的元素。因此对每个元素x我们可以单独考虑。如果x被转换,则费用会减去前面偏移比它小的元素数目,同时加上后面偏移比它小的元素数目。因此我们可以直接确定每个元素是否被转换。

最后跑一次标准求逆序对的算法即可。总的时间复杂度为O(nlog2n)

字符串转换最少交换次数

给定长度为n的字符串st,每个字符在两个字符串中出现次数相同。现在要求你通过下面操作将字符串s转换成t

  • 每次挑选一个i,满足1i<n,交换sisi+1

问最少需要执行多少次操作。

首先我们交换的两个相邻字符肯定是不同的,因此我们知道si实际对应的是tπ(i)

下面我们重新来解读这个问题,有一个置换a1,,an,其中ai=π(i),要求我们通过邻位交换的技术将数组进行排序。这个问题我们实际上已经提到过了,就是排序最少交换次数。

提供一道题目