moset的个人博客分享 http://blog.sciencenet.cn/u/moset 以心为绢,绘山河;以思为海,汇百流;以文为宴,会高朋。

博文

排列组合的几个程序

已有 6536 次阅读 2014-1-14 09:50 |系统分类:科研笔记| MATLAB, 排列, 程序

       有n个不同球,从中选择m个,不考虑选择的顺序,可以列出多少种选择?这问题是简单的,若n阶乘表示为:fact(n),且把问题记作C(n,m)。那么:C(n,m) = fact(m)/fact(n)/fact(n-m) 。当用程序直接列出所有可选,虽然不难,可以直接想到排列加剔除的方式,然而这样的程序显然是非常的丑陋的。应该得有好点的算法去解决它:对球编号1:n,问题等价从1:n中选择m个不同的数字。假设C(n,m-1)的排列已知,则每一种排列{a,b,c,…x}衍生C(n,m)的排列{a,b,c…x,y},其中y(x+1):n中的任意,共衍生排列n-x项。注:要求每列的数字顺序为增序,即a<b<c…

MATLAB程序描述:

function re=getspre(n,m)

re=(1:n)';

while(size(re,2)<m)

   tmp=[];

   for i=1:size(re,1)

      tmp=[tmp;[ones(n-re(i,end),1)*re(i,:),(re(i,end)+1:n)']];

   end

   re=tmp;

end

end

>> getspre(5,3)

ans =

   1     2     3

   1     2     4

   1     2     5

   1     3     4

   1     3     5

   1     4     5

   2     3     4

   2     3     5

   2     4     5

   3     4     5

       算法要求每个排列是单调递增序列,则令所有选择无重复,对于任意可能出现在C(n,m)的序列必然有C(n,m-1)的源所以选择没有遗漏。算法结构描述排列数量是以如下方式增长的:,共有求和号m-1个。

例: 

   

       另,对于问题:有n个编号不同的球,可以有多少种不同的顺序排列方式?记为P(n)。那么列出P(n)的全部排列可以有很多种方式列出,但程序的结构应力求用更少的时间复杂度,以及更少的内存资源。下面是一个方式,用MATLAB描述:

function H=sepn(n)

if(n==1)

   H=1;

   return;

end

regu=sepn(n-1);

H=[];

x=[1:n,1:n];

for i=2:n

   tx=x(i:i+n-2);

   H=[tx(regu);H];

end

H=[regu;H];

L=reshape(ones(size(regu,1),1)*(n:-1:1),[],1);

H=[H,L];

end  

>> sepn(3)

ans =

   1     2     3

   2     1     3

   3     1     2

   1     3     2

   2     3     1

   3     2     1

       假设P(n-1)的排列已知,序列T={1,2,…n,1,2,…n},那么做序列Xi={T(i),T(i+1),T(i+2)…T(i+n-2)},其中i=1:n。对所有Xi序列进行P(n-1)排列,所有得到的序列末位最后补上T(i+n-1)。算法不需要任何多余的判断和剔除,而且存储结构上也不需要多余的资源,最后的到的数组所有位在整个过程中都只赋值一次。方式用C++或者JAVA来做会看到更简易结构:

package amk2;

publicclass funcs {

   public  int [][]px;

   public  int n;

   public  int T;

   public funcs(int a){

      int i;

      T=1;

      for(i=1;i<=a;i++) T*=i;

      n=a;

      px=new int [T][n];

   };

   public void exe()

   {

      int i,j,t;

      int k;

      int ln=1;

      int []tmp;

      tmp=new int [2*n];

      px[0][0]=0;

      //******************** M *************************

      for(k=1;k<n;k++)

      {

          for(i=0;i<=k;i++)

          {

             tmp[i]=i;

             tmp[i+k+1]=i;

          }

          for(t=1;t<=k;t++)

          {

             for(i=0;i<ln;i++)

             {

                 for(j=0;j<k;j++) px[ln*t+i][j]=tmp[px[i][j]+t];

                 px[ln*t+i][k]=t-1;

             }

          }

          for(i=0;i<ln;i++) px[i][k]=k;

          ln*=(k+1);

      }

      //******************** M ***************************

      for(i=0;i<T;i++)

      {

          for(j=0;j<n;j++)

          {

             System.out.print(px[i][j]);

             System.out.print(' ');

          }

          System.out.print((char)0x0d);

      }

   }

}

程序中的M段描述的就是这个算法结构。

funcs abc = new funcs(3);

则:

0 1 2

1 0 2

1 2 0

2 1 0

2 0 1

0 2 1

       最后若是问题是所有n个编号的球,取出m个排列,允许重复?有上述的两个接口程序,得到这个问题的程序解答很容易,这儿就不列出了。

**************************************************************************************

       在做P(n)时,曾想过用第n数插入到所有P(n-1)的排列的各个间隔中,很容易理解,问题是这样的结构需要链表,不是一个好的方式。常常有些有意思的东西,只是抬笔很麻烦,好在昨夜失眠,还是写点什么好了。



https://blog.sciencenet.cn/blog-567861-758943.html

上一篇:曾经的语文课上(排序问题)
下一篇:(y^a)(mod k)的程序
收藏 IP: 218.24.71.*| 热度|

0

该博文允许注册用户评论 请点击登录 评论 (0 个评论)

数据加载中...

Archiver|手机版|科学网 ( 京ICP备07017567号-12 )

GMT+8, 2024-11-23 03:21

Powered by ScienceNet.cn

Copyright © 2007- 中国科学报社

返回顶部