1.生成1~n的排列
1)題解
循環變量i是當前考察的A[cur]。爲了檢查元素i是否已經用過,上面的程序用到了一個標誌變量ok,初始值爲1(真),如果發現有某個元素A[j]=i時,則改爲0(假)。如果最終ok仍爲1,則說明i沒有在序列中出現過,把它添加到序列末尾(A[cur]=i)後遞歸使用。
聲明一個足夠大的數組A,然後調用print_permutation(n,A,0),即可按字典序輸出1~n的所有排列。
2)代碼
void print_permutation(int n,int *A,int cur){
if(cur==n){
for(int i=0;i<n;i++){
printf("%d ",A[i]);
}
printf("\n");
}
else{
for(int i=1;i<=n;i++){
int ok=1;
for(int j=0;j<cur;j++){
if(A[j]==i){
ok=0;
break;
}
}
if(ok){
A[cur]=i;
print_permutation(n,A,cur+1);
}
}
}
}
2.生成可重集的排列
1)題解
需要注意兩點
- 取消“禁止A數組中出現重複”,因爲P中本來就有重複元素,依然保留這個禁令,明顯是錯誤的。一個解決方案是統計A[0]~A[cur-1]中P[i]的出現次數c2以及數組P中P[i]的出現次數c1,只要c1>c2,就可以繼續遞歸下去。
- 我們枚舉的下標i應不重複、不遺漏地取遍所有P[i]。由於P數組已經排序過,所以只需檢查P的第一個元素和所有“與前一個元素不相同”的元素。
2)代碼
void print_permutation(int n,int *P, int* A, int cur){
if(cur==n){
for(int i=0;i<n;i++){
printf("%d ",A[i]);
}
printf("\n");
}
else{
for(int i=0;i<n;i++){
int c1=0,c2=0;
//當i=0時,P[i]!=P[i-1]不會被執行,所以不會發生數組越界的問題。
if(!i||P[i]!=P[i-1]){
for(int k=0;k<n;k++){
if(P[i]==P[k]){
c1++;
}
}
for(int k=0;k<cur;k++){
if(P[i]==A[k]){
c2++;
}
}
if(c2<c1){
A[cur]=P[i];
print_permutation(n,P,A,cur+1);
}
}
}
}
}