帶重復的全排列問題


  明白帶重復的全排列首先要明白不帶重復的全排列(不帶重復的全排列鏈接

  在不帶重復的全排列中說到在排列1,2,3,4插入5有5種方式,會生成5種新的排列。

  如果我們在1,1,2,3中插如4也有五種方式,

(1)4,1,1,2,3

(2)1,4,1,2,3

(3)1,1,4,2,3

(4)1,1,2,4,3

(5)1,1,2,3,4

  生成了五種排列

  但如果在1,2,3,4中插如1

(1)1,1,2,3,4

(2)1,1,2,3,4

(3)1,2,1,3,4

(4)1,2,3,1,4

(5)1,2,3,4,1

  雖然有五種插入方式,但是發現生成的第一種排列和第二種排列是相同的,只生成了四種排列

  現在我們定義f(i)為第一位到第i-1位中有f(i)個元素與第i位的元素相同那么一段數字所生成的全排列種數為∏(i-f(i))

  如1,1,2,2,3,3的全排列,(1-0)*(2-1)*(3-0)*(4-1)*(5-0)*(6-1)=175

代碼分析:

  以1,1,2,3為例,建一顆搜索樹(不明白的可以點這里

  這樣做肯定會產生重復的排列,現在要做的就是找到重復的元素並去掉。首先看那些排列時重復的。

  黃色標注,代表這些排列都是重復的,不難發現,重復的排列都是同根節點的子節點出現重復時,以這個子節點為跟 的子樹就會產生重復。所以保證每一行每種元素不出現兩次(同一根節點的時候)

代碼實現:

#include <algorithm>
#include <iostream>
#include <cstring>
#include <vector>
#include <cstdio>

using namespace std;
int n;
void print(const int a[]){
    for(int i=0;i<n;i++){
        printf("%d",a[i]);
    }
    printf("\n");
}

void f(int a[],int x){
    if(x==n)print(a);
    else{

        for(int i=x;i<n;i++){int o=0;
            for(int j=x;j<i;j++){
                if(a[i]==a[j]){
                    o=1;
                    break;
                }
            }
            if(o==0){
                swap(a[x],a[i]);
                f(a,x+1);
                swap(a[x],a[i]);
            }

        }
    }
}

int main()
{
    int a[10];
    scanf("%d",&n);
    for(int i=0;i<n;i++){
        scanf("%d",&a[i]);
    }
    f(a,0);
    return 0;
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM