源于论坛一个帖子,从一个各元素不同的偶数个元素数组(比如[1 2 3 4 5 6])中任取两个元素的组合,然后将这些所有两个元素的组合分成若干组,每组都能重新组成新数组,而这个新数组正好与原来数组相同,问当这个偶数数组是1-100时,一共能排列成多少种,并一一列举出来。
论坛回复有两种比较好的方法,我只看懂了一种,发下:
比如数组1-6,[1 2 3 4 5 6],任意取两个元素一共有12,13,14,15,16,23,24,25,26,34,35,36,45,46,56十五种(6*5/2),将这十五个新元素可以不重复的组成5组新数组和原来一样,他们是:[12 34 56]、[13 25 46]、[14 26 35]、[15 24 36]、[16 23 45]——正好全部用完十五种不重复;
这其实是一个循环赛问题,解决办法如下:
1、取1、n,2、n-1...分别形成组合
2、固定一个元素,使其他的元素做循环左移或右移,移动一次后再按1进行处理,直循环完。
举例如下:
1: 123456->1:6,2:5,3:4
固定 1,循环其他
2: 162345->1:5,6:4,2:3
3: 156234->1:4,5:3,6:2
4: 145623->1:3,4:2,5:6
5: 134562->1:2,3:6,4:5
于是得到一种组合方式,按以下规则可以得到其他组合
法1: 使1与其他5个数互换,可以得到五种
法2: 除1外的其他5个数与相临数互换,可以得到五种
法3: 除1外的其他5个数与间隔一个的数互换,又可以得到五种。
因为是循环数,间隔再大时与以上重复。
于是共有15种不同的组合
还有这么一个算法,没看懂,有机会再研究一下:
花了一天时间看了一下算法2 ,稍微有点懂了。
第二个算法中ci++ <=> ci = 2*j +(i-j)+1,而ci=ci-(m-j) <=> ci=2*j-1。这里将ci代入前式,并注意到两者的i差1便可以得出。
这种表达式变换对理解程序很有帮助。
设编号分别为1..n的n个人分组,其中n-2个人定了,则分组方式也就定了。取第1人与他人结合,
有1:2,1:3,...,1:n 共n-1组,每组两个编号的“和”从3..1+n,连续,对n-1取模得0..n-1,没有重复,正好n-1组。
现在不考虑n,任取两个数求其和并对n-1取模,设其结果为a则放到第a组,如果可得到n-1组,其中每组有n-2个值,这样就确定了分组。
如 12 35 46 :3
13 45 26 :4
14 23 56 :5
15 24 36 :6
16 25 34 :7
第二个算法便是在此基础上分组的,不同的是它可以直接将每组最后一个组合(与n结伴的人)直接分到相应的组中。
其实n与1地位相当,因为n mod(n-1)=1,因此每组最后一个组合由与n结伴的人的编号确定,由程序可以看出,它们被分到
(2*j) mod (n-1)这一组,其中j等与n结伴的人的编号-1。