关于一个求最小交换次数的算法的一个严格证明,是严格证明,不是想当然

问题描述:

有一个1~n的数列的排列,但是这个数列已经被打乱了排列顺序,如果我们只是通过“交换任意两个元素”,那么,要实现元素从1~n的有序排列,“最少的交换次数是多少?”

解答过程:

首先我们纸上可以先写写简单的情况试试,比如排列:4 3 1 2, 交换次数=3;我们可以在多组测试中,边测试边想,真正的实现需要满足:4本该到2处, 2本该到3处, 3本该到1处, 1本该到4处,刚好一个循环。

于是,考虑:

引理:是否对于满足这种一个循环的排列,最少交换次数等于元素个数减去1呢?

可以考虑数学归纳法。

首先k=1,2,3时我们可以知道是成立的;

假设当 n <=k 时, 这种单循环排列的最少交换次数为n-1;

考虑n=k+1的情况: 这时,我们任意交换k+1个中的两个元素,会发现单循环分裂成了两个单循环(比如上述,4和1交换后,序列变成 1 3 4 2 此时 剩下了<1> 和 <3 4 2>两个子序列, <1>交换次数=0 <3 4 2>交换次数=2,那么总的交换是3次;如果我们交换1和2(本次交换没有任何一个元素归位),剩下的是序列4 3 2 1 ,是两个单循环序列<4 1>和<3 2>,总的交换还是1+(1+1) = 3  = 4 -1),那么接下来有两种做法:

方法1:对两个单循环序列分别执行递归调用,则最小交换次数为1 + (序列1的个数-1) + (序列2的个数-1) = 元素总数-1

方法2:我们把分开的两个单循环序列进行合并交换,即序列1中的元素和序列2中元素交换,交换后新的合成序列出来了,这种交换将原始序列分开了又合并,白白交换了2次,剩下的序列还是k+1个单循环,这种交换显然不是最优的交换方式

由此看来,方法1的交换是通往最少交换的交换方式。

说明当n=k + 1时,我们按照方式1就可以更优的交换, 此时可以保证交换次数=k=n-1次

至此我们证明了:单循环序列,最少交换次数为n-1次。

考虑多个单循环序列的情况

由于不同的两个单循环序列合并交换称一个单循环序列时,有上述方法2可知其实是无效交换

所以,多个单循环序列的交换情况,就是每个单循环序列各自交换的次数的相加之和

比如 4 3 2 1 7 6 5

就是两个单循环序列<4 3 2 1> <7 6 5>的各自交换次数之和 = 3 + 2  = 5 = 7 - 单循环序列的个数

由此可知, 对于一个n长的互异序列, 通过交换实现有序的话,最优的交换次数是=n - n被分解成单循环的个数

明白了这个过程,代码自然都是浮云。。。

时间: 2024-11-09 09:49:43

关于一个求最小交换次数的算法的一个严格证明,是严格证明,不是想当然的相关文章

neu 1493 Caoshen like math(最小交换次数)

http://acm.neu.edu.cn/hustoj/problem.php?cid=1047&pid=4 题意:数字1到n 任意排列 求排列成有序序列最少交换次数 思路:求最小交换次数有两种 1 交换的两数必须相邻  (poj 2299) 通过归并排序求出其逆序数即为所求值 证明:可以先将最大数交换到最后,由于是相邻两个数交换,需要交换的次数为最大数后面的数的个数(可以看做是最大数的逆序数),然后,交换过后,去除最大数,再考虑当前最大数也需要其逆序数次交换.则每个数都需要交换其逆序数次操作

Cycle Sort (交换次数最少的排序)

该算法的效率并不高.但是却提供了一个很好的思路.如何让一个序列在最小交换次数下实现有序. Cycle Sort 翻译成中文是 圈排序. 这个圈在于需要交换的数据形成圈. 具体一点: 如: Array  4 3 2 5 5 6  要处理的数组 Result 2 3 4 5 5 6  结果 pos     0 1 2 3 4 5  下标 从下标0的元素开始观察.4 需要到下标 2 而下标2的元素为 2 需要到下标0 .刚好可以回到4. 也就是形成了 4-2 这样的圈 接下来是3 需要到下标1 而3本

冒泡排序的交换次数

题意: 给定一个1~n的排列a0,a1,-an-1,求对这个数列进行冒泡排序所需要的交换次数(冒泡排序是每次找到满足ai>ai+1的i,并交换ai和ai+1,直到这样的i不存在为止的算法). 限制条件:1<= n<= 100000 输入: n=4, a={3,1,4,2} 输出: 3 冒泡排序的复杂度是O(n2),所有无法通过模拟冒泡排序的过程来计算需要的交换次数.不过我们可以通过选取适当的数据结构来解决这个问题. 首先,所求的交换次数等价于满足i<j,ai>aj的(i,j)

【POJ1681】Painter&#39;s Problem 高斯消元,求最小∑系数的异或方程组

#include <stdio.h> int main() { puts("转载请注明出处[vmurder]谢谢"); puts("网址:blog.csdn.net/vmurder/article/details/43483547"); } -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 题意: 多组数据. 有个n*n的正方形,然后你要对某些位置进行操作,使得最后灯的状态都变成y.

使序列递增的最小交换

我们有两个长度相等且不为空的整型数组 A 和 B . 我们可以交换 A[i] 和 B[i] 的元素.注意这两个元素在各自的序列中应该处于相同的位置. 在交换过一些元素之后,数组 A 和 B 都应该是严格递增的(数组严格递增的条件仅为A[0] < A[1] < A[2] < … < A[A.length - 1]). 给定数组 A 和 B ,请返回使得两个数组均保持严格递增状态的最小交换次数.假设给定的输入总是有效的. 示例: 输入: A = [1,3,5,4], B = [1,2,

HDU1394 线段树求最小逆序数

题目:http://acm.hdu.edu.cn/showproblem.php?pid=1394 求最小的逆序数,在此贴下逆序数的概念: 在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序.一个排列中逆序的总数就称为这个排列的逆序数.逆序数为偶数的排列称为偶排列:逆序数为奇数的排列称为奇排列.如2431中,21,43,41,31是逆序,逆序数是4,为偶排列. 也是就说,对于n个不同的元素,先规定各元素之间有一个标准次序(例如n个 不同的自然数,可规

Poj 1815 Friendship 枚举+求最小割

给以一个图和两个点S,T,问你拿掉最少多少个点可以使得S和T不连通.输出点数并且输出拿掉的是哪些点,如果有多种方法就输出字典序最小的那个. 这就是一个求最小点割集的问题.无向(有向)图G中,给定源点s和终点t,至少要删去多少个点(具体一点,删哪些点),使得s和t不连通.这个问题就是点连通度,也叫最小点割集. 解法其实理解起来不难,只要把图中的每一个点v拆成v',v''两个点,并建立<v',v''>权为1,这样就把最小点割集转化成求最小割的问题. 对于原图的转化也很简单,对于原来的每条边,转化成

如何求最小三元组距离

题目描述: 已知三个升序整数数组a[l], b[m]和c[n].请在三个数组中各找一个元素,使得组成的三元组距离最小. 三元组的距离定义是:假设a[i].b[j]和c[k]是一个三元组,那么距离为:Distance = max(|a[i]–b[j]|,|a[i]–c[k]|,|b[j]–c[k]|)请设计一个求最小三元组距离的最优算法,并分析时间复杂度. 关键公式:max(|a[i]–b[j]|,|a[i]–c[k]|,|b[j]–c[k]|) = (abs(a[i]-b[j])+abs(a[i

阿里巴巴笔试题求最小三元组距离

已知三个升序整数数组a[l], b[m]和c[n].请在三个数组中各找一个元素,是的组成的三元组距离最小.三元组的距离定义是:假设a[i].b[j]和c[k]是一个三元组,那么距离为: Distance = max(|a[ I ] – b[ j ]|, |a[ I ] – c[ k ]|, |b[ j ] – c[ k ]|) 请设计一个求最小三元组距离的最优算法,并分析时间复杂度. #include<iostream> using namespace std; int Max(int a,i