暴力求解法

1.生成1~n的排列

1)題解

\quad循環變量i是當前考察的A[cur]。爲了檢查元素i是否已經用過,上面的程序用到了一個標誌變量ok,初始值爲1(真),如果發現有某個元素A[j]=i時,則改爲0(假)。如果最終ok仍爲1,則說明i沒有在序列中出現過,把它添加到序列末尾(A[cur]=i)後遞歸使用。
\quad聲明一個足夠大的數組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);
                }
            }
        }
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章