Chinaunix首页 | 论坛 | 博客
  • 博客访问: 828880
  • 博文数量: 330
  • 博客积分: 9641
  • 博客等级: 中将
  • 技术积分: 3181
  • 用 户 组: 普通用户
  • 注册时间: 2007-01-19 14:41
文章分类

全部博文(330)

文章存档

2012年(17)

2011年(135)

2010年(85)

2009年(57)

2008年(36)

我的朋友

分类:

2011-12-21 00:51:41

来源:http://llfclz.itpub.net/post/1160/278490
一个经典的全排列算法

设想有 n 个数字, 先取第一个数字. 再取第二个数字, 第二个数可以放在第一个数的左或右面, 就是有 0, 1 两个选择. 再取第三个数, 放到前面选好的两个数字中, 可以放在最左, 中间, 最右, 就是有 0, 1, 2 三个选择. , 很自然吗. 忽然你想到了二进位, 八进位那些数系转换关系。可以设计这样一个数, ...xyz, 其中个位数 z 是二进位的, 也就是放第二个数的两个位置; 十位数 y 是三进位的, 代表放第三个数字的三个位子, 然后百位数是四进位, 千位数是五进位的, 依以类推." 没错, 这样设计的话, 如果 0 表示放於最左面的话,  "2021" 这个数就代表了排列五个元素 (abcde), 取一个a, 然后第二个 b 放在 a 的右面成 ab,  c 放到最右面成为 abc,  d 放到最左面成 dabc; 最后 e 放到中间去成为 daebc. 至於 "2021" 这个特别的设计的数可以用2*5+ 0*4 + 2*3 + 1*2 这样的计算来映对到自然数的数列上去。

如求 4 个数的 4! = 24 个排列,  18 个排列可以这样求得, 18  2, 余数是 0, 所以第二个数放在第一个数的左面; 然后商 9 再除 3, 余数 0,所以第三个数於在头两个数的最左; 最后 3 除以 4, 余数是 3, 因此第四个数要放在前三个数的第 4 个空位, 也就是最右面。


来源:http://www.cnblogs.com/nokiaguy/archive/2008/05/11/1191914.html
1、首先看最后两个数4, 5。 它们的全排列为4 5和5 4, 即以4开头的5的全排列和以5开头的4的全排列。
由于一个数的全排列就是其本身,从而得到以上结果。
2、再看后三个数3, 4, 5。它们的全排列为3 4 5、3 5 4、 4 3 5、 4 5 3、 5 3 4、 5 4 3 六组数。
即以3开头的和4,5的全排列的组合、以4开头的和3,5的全排列的组合和以5开头的和3,4的全排列的组合.
从而可以推断,设一组数p = {r1, r2, r3, ... ,rn}, 全排列为perm(p),pn = p - {rn}。
因此perm(p) = r1perm(p1), r2perm(p2), r3perm(p3), ... , rnperm(pn)。当n = 1时perm(p} = r1。
为了更容易理解,将整组数中的所有的数分别与第一个数交换,这样就总是在处理后n-1个数的全排列。

  1. #include<stdio.h>
  2. void swap(char *a,char *b)
  3. {
  4. char t;
  5. t = *a;
  6. *a = *b;
  7. *b = t;
  8. }
  9. void print(char *a,int l)
  10. {
  11. int i = 0;
  12. for(;i<l;++i)
  13. printf("%c",a[i]);
  14. printf("\n");
  15. }
  16. void permut(char * a,int p,int q,int length)
  17. {
  18. int i = 0;
  19. for(i = p;i<=q;++i)
  20. {
  21. swap(&a[i],&a[p]);
  22. if(p == q)
  23. print(a,length);
  24. permut(a,p+1,q,length);
  25. swap(&a[i],&a[p]);
  26. }

  27. }
  28. int main()
  29. {
  30. char a[4] = {'a','b','c','d'};
  31. permut(a,0,3,4);
  32. return 0;
  33. }

阅读(649) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~