您的位置:首页 > 其它

一种约束排列的生成算法

2007-10-04 17:53 393 查看
一种约束排列的生成算法

陈兆斗、柯爱荣

《工程数学学报》

本文所述的约束排列是指: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
;






bool Is_Max_Permutation( int index )...{//index : 头位置, 0表示开始于list[0]


int i, sum=restraint
;


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
;


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;


}

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: