n進制法
這個演算法是將初始排列012……(n-1)作為乙個n進製數,然後對它累加1,從而生成全體排列。這個演算法比較簡單,但是在累加過程中,會出現重複元素,所以需要將有重複元素的排列刪除。這是這個演算法的缺點。
從乙個排列生成乙個新的排列的演算法如下:
第一步:在排列的第n-1 位累加1。
第二步:如果其和大於n-1,就進製,發生連續進製就連續進製直至不再發生進製為止。無進製繼續。
第三步:檢查排列中有無重複元素,如果有則直接返回第一步;如果無則輸出乙個排列。
要產生n個元素的全排列,可以從原始排列01……(n-1)開始,對第n-1位累加
1,產生乙個新的排列後就輸出,然後返回重複以上步驟,直到排列的第乙個元素超過n-1時停止。 以3
個數0、1、2
的排列為例:原始排列是
1 2 3,從它開始,最後乙個元素是3,加上1則有
3+1=4,4>3,進製,前面乙個元素是2,進製後2+1=3,所以新排列是1 3 1,這個排列有重複元素,將它拋棄,繼續對最後乙個元素加
1,……。按照這個訪法,順序產生的排列是:1 2 3,1 3 2,1 3 3,2 1 1,2 1 2,2 1 3,2 2 1,2 2 2,2 2 3,2 3 1,2 3 2,2 3 3,3 1 1,3 1 2
,3 1 3,3 2 1
,3 2 2,3 2 3,3 3 1,3 3 2,3 3 3,4 1 1,這時第乙個元素大於3
,程式結束。把其中有重複元素的排列去掉,就得到了三個元素的排列。有下劃線的排列中存在重複元素,丟棄,餘下的就是全部排列。
需要注意,這裡並非嚴格意義的n進製數,因為每一項進製時是在該項大於n才發生。這樣做的目的是為了保證按照給定元素實現排列。
//n進製演算法
//輸入:排列元素個數n
//輸出:
n個元素的排列
#include
#include
using namespace std;
void perm(int *p,int n);
void output(int *p,int n);
int repeat(int *p,int n);
int total;
int main()
freopen("in.dat","r",stdin);
int n,*p;
while(cin>>n)
p=new int[n];
for(inti0;i陣列初始化
p[i]=i+1;
total=0;
perm(p,n);
return 0;
void perm(int *p,int n)
while(1)
if(!repeat(p,n)) //排列中無重複元素
output(p,n); //輸出乙個排列
int i=n-1; //在排列末尾累加1
p[i]++;
while(p[i]>n && i>0) //有進製向前進製
p[i--]-=n;
p[i]++;
if(p[0]>n) //排列第一位大於n
return; //結束
void output(int *p,int n)
coutfor(int i=0;ifor(int j=i+1;jif(p[i]==p[j])
return 1;
return 0;
N個數的全排列
我採用的方法是類似密碼箱的轉輪來得到所有的排列組合 比如求 1,2,3,4的所有排列組合 採用遞減式輪轉來生成 n 4 以1234為初始值 得到如下的所有4個組合,放入最終的容器中 1 2 3 4 2 3 4 1 3 4 1 2 4 1 2 3 n 3 以上面的四個作為初始值,在第三位開始輪轉 得到...
N個數全排列的非遞迴演算法
n個數全排列的非遞迴演算法 include stdio.h voidswap int a,int b 根據當前的排列p,計算下乙個排列。原則是從1234 4321,若p已經是最後乙個排列,傳回false,否則傳回true。p是乙個n維向量。boolnextpermutation int p,intn...
全排列演算法的字典序排列
之前在中描述了全排列演算法的遞迴解法,這裡再說一種演算法 字典序排列。字典序排列就是按照字典a z,1 9的順序給出字串的順序全排列,例如abc的全排列就是從abc一直排到cba。那麼給定乙個字串,怎麼找出恰好大於該字串的下乙個排列呢?我們考慮如下的步驟 1 假設字串為p1p2 pn,我們從後往前尋...