一种约束排列的生成算法

转载 2007年10月04日 17:53:00

        一种约束排列的生成算法 

                                                                 陈兆斗、柯爱荣

                                                《工程数学学报》

本文所述的约束排列是指:m个非负整数所构成的排列a1a2...am,满足约束条件:a1<=N1,a2<=N2,...,am<=Nm及a1+a2+...+am=M,其中M和N1,N2...  ,Nm是给定的正整数。

算法描述:

算法设计的主要思想来源于p进制整数的进位方法。所不同的是各个位上的进制不同,并有约束条件a1+a2+...+am=M。将上述所有的约束排列记为( |N1,N2...  ,Nm|;M )。其中按照字典排序法,最大排列记为max{ |N1,N2...  ,Nm|;M },最小排列记为min{ |N1,N2...  ,Nm|;M}。下面的数据表是一个具体的约束排列(|3 4 2 3|;9}的所有结果,它们是按字典排序法依照升序给出的。其中最后一列是按照各个排列的次序由小到大所给出的标号:

0  4  2  3                            1
1  3  2  3                            2   
1  4  1  3                            3
1  4  2  2                            4
2  2  2  3                            5
2  3  1  3                            6
2  3  2  2                            7
2  4  0  3                            8
2  4  1  2                            9
2  4  2  1                           10
3  1  2  3                           11
3  2  1  3                           12
3  2  2  2                           13
3  3  0  3                           14
3  3  1  2                           15
3  3  2  1                           16
3  4  0  2                           17
3  4  1  1                           18
3  4  2  0                           19

显然,表中的最大排列为第19号排列3420;最小排列为第1号排列0423。我们对算法的要求是输入其中的任何一个排列,算法按字典排序法自动生成下一个排列,例如:输入第7号排列2322,则应输出第8号排列2403,算法分为以下几个步骤:

1):输入排列a1a2...am,并检验该排列是否满足约束要求。

2):从排列a1a2...am最右边的个位向左依次判断ajaj+1...am是否为约束排列( |Nj,Nj+1...  ,Nm|;Mj ),其中Mj=M-(a1+a2+...+aj-1),j=m,m-1,...,2,1。

3):在上述依次取j=m,m-1,...,2,1的过程中,设k为上述过程中第一个不是约束排列( |Nk,Nk+1...  ,Nm|;Mk )的最大排列的位。即akak+1...am不是( |Nk,Nk+1...  ,Nm|;Mk )的最大排列,而对于i=k+1,k+2,...  ,m,aiai+1...am都是( |Ni,Ni+1...  ,Nm|;Mi )的最大排列。

4):如果k=0则终止。否则,将ak改为ak`=ak+1,取排列ak+1`ak+2`...am`=min{ |Nk+1,Nk+2...  ,Nm|;Mk`},其中Mk`=M-(a1+a2+...+ak-1+ak`)。

5):生成的下一个排列就是:a1a2...akak`ak+1`ak+2`...am`

可以看到在此算法中,最大、最小排列起到重要作用,因为它们的算法都比较简单,在本文中从略。

附:C++实现代码:

 

#include <cstdlib>
#include 
<iostream>

using namespace std;

const int n=4;
int   restraint[n+1]={3,4,2,3,9};
int   list[n];

bool  Is_Max_Permutation( int index ){//index : 头位置, 0表示开始于list[0] 
      int  i, sum=restraint[n];
      
for( i=0; i<index; ++i )
           sum
-=list[i];
      i
=n-1;
      
while( i>=index ){
             
int  j, temp=0, mid;
             
for( j=index; j<i; ++j )
                  temp
+=restraint[j];
             temp
=sum-temp;
             mid
=temp>0? temp : 0;
             
if( mid!=list[i] )
                 
return false;
             sum
-=mid;
             
--i;
      }

      
return true;
}


void  Get_Min_Permutation( int index ){//index : 头位置, 0表示开始于list[0]
      int  i, sum=restraint[n];
      
for( i=0; i<index; ++i )
           sum
-=list[i];
      i
=index;
      
while( i<=n-1 ){
             
int j, temp=0;
             
for( j=n-1; j>i; --j )
                  temp
+=restraint[j];
             temp
=sum-temp;
             list[i]
=temp>0? temp : 0;
             sum
-=list[i];
             
++i;
      }

}
    

bool  Next_Permutation( ){
      
int  i=n-1;
      
while( Is_Max_Permutation( i ) && i>=0 )
             
--i;
      
if( i<0 )
          
return false;
      list[i]
++;
      Get_Min_Permutation( i
+1 );
      
return true;
}

                    
int main(int argc, char *argv[])

    Get_Min_Permutation( 
0 );
    
int  i;
    
do
    
{
      
for( i=0; i<n; ++i )
           cout
<<list[i]<<"  ";
      cout
<<endl;
    }
while( Next_Permutation( ) );
    system(
"PAUSE");
    
return EXIT_SUCCESS;
}

相关文章推荐

一种新的全排列生成算法

一种新的全排列生成算法  算法原理:        对集合S={a1,a2,...,an},假设已经知道前n-1个元的全排列,那么,这n个元素的全排列{p1,p2,...,p(n-1)...

一种基于归并排序及随机数生成器对一个给定数组进行随机排列的算法

在编程应用中,我们常常需要得到一个给定序列的随机排列。有一种方法是利用编译环境提供的随机数生成器生成一个与目标序列容量相同的随机数序列,随机数的值表示目标序列中对应项的优先级。如果我们排列随机数序列使...

使用set实现的一种简单的全排列算法(C++语言)

本算法的思想十分简单。
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)