日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

排列组合(两种方法)

發布時間:2024/1/18 编程问答 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 排列组合(两种方法) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

排列組合是組合數學的基礎,從n個不同元素中任取m個,約定1<m≤n,按任意一種次序排成一列,稱為排列,其排列種數記為(Arrange)A(n,m)。從n個不同元素中任取m個(約定1<m<n)成一組,稱為一個組合,其組合種數記為C(n,m)。計算A(n,m)與C(n,m)只要簡單進行乘運算即可,要具體展現出排列的每一列與組合的每一組,決非輕而易舉。
注意:
1、 排列A有序 A(n,m) = n * (n-1) * …*(n-m+1)
2、 組合C無序 C(n,m) = A(n,m) / A(m,m)
3、 注意到組合與組成元素的順序無關,約定組合中的組成元素按遞增排序。因而,把以上程序中的約束條件作簡單修改: a[i]==a[j] 修改為 a[i]>=a[j]
有兩種方法:
1、DFS方法適用于不重復的情況下,分治法可適用于有元素相同的情況下
2:分治法元素相同時的情況為:
//1、arr[i]!=arr[k],因為這樣交換后剩下的元素是一樣的,兩種全排列是重復的
//2、arr[k+1]—>arr[i-1],也就是k和i之間的元素不能和arr[i]相等,因為k和i之間的元素都是和k交換過的,
//如果arr[i]和arr[k+1]—>arr[i-1]之間的元素有相等的,那么這兩種排列也是重復的
//下面代碼中||運算前的是第一種情況,或運算之后的是第二種情況

排列:DFS 方法一:回溯法(全排列的數組中不可以有重復的元素) /*1-n中m個數的全排列*/ #include <iostream> #include <vector>using namespace std; int count = 0; vector<int> v;bool Single(int num) {for (int i=0; i<v.size(); ++i){if (v[i] == num)return false; }return true; } //全排列 void perm(int n, int m) {if (m == 0){++count;return;}for (int i=1; i<=n; ++i) {if (Single(i)){v.push_back(i);perm(n, m-1);v.pop_back(); }} }int main() {int n, m;cin >> n >> m;perm(n, m); cout << count << endl;return 0; } 回溯法:組合(組合的數組中不可以有重復的元素) /*1-n中m個數的組合*/ #include <iostream> #include <vector>using namespace std; int count = 0; vector<int> v;bool Single(int num) {for (int i=0; i<v.size(); ++i){if (v[i] == num)return false; }return true; } //組合 void perm(int n, int m) {if (m == 0){++count;return;}for (int i=1; i<=n; ++i) {if (Single(i)){v.push_back(i);perm(n, m-1);v.pop_back(); }} }int main() {int n, m;cin >> n >> m;perm(n, m); cout << count << endl;return 0; } 全排列方法二:分治法(數組中可以有重復元素,下一個程序就是怎樣消除重復) #include <iostream>using namespace std; int count = 0;void swap(int* arr, int i, int j) {arr[i] = arr[i] ^ arr[j];arr[j] = arr[i] ^ arr[j]; arr[i] = arr[i] ^ arr[j]; }void perm(int* arr, int len, int m, int n) {//生成了一種全排列 if (m == n){++count;return; }for (int i=m; i<=n; ++i){swap(arr, m, i);perm(arr, len, m+1, n); swap(arr, m, i); } }int main() {int arr[9];for (int i=0; i<9; ++i){arr[i] = i+1; }perm(arr, 9, 0, 8); cout << count << endl;return 0; } 分治法:全排列(數組中可以有重復的元素ADCD) #include <iostream> #include <string>using namespace std; string str; string* pwd; int n; int count = 0;void swap(int index, int i, int j) {char tmp = pwd[index][i];pwd[index][i] = pwd[index][j];pwd[index][j] = tmp; }//判斷是否重復出現 //一般的全排列算法只能排列數組中沒有重復的數字或字母 //但是如果出現重復的情況下比如aaaabbbb進行全排列,好多排列雖然看似不重復,但是結果是重復的 //這種方法進行全排列時(分治法),從1-n個元素中選n次,每次選1個之前不同的數,然后對剩下的數進行全排列 //也就是perm(R)=(r1)perm(R1),(r2)perm(R2),(r3)pwem(R3)....(rn)perm(Rn) //每次i和k交換的時候,重點是: //1、arr[i]!=arr[k],因為這樣交換后剩下的元素是一樣的,兩種全排列是重復的 //2、arr[k+1]--->arr[i-1],也就是k和i之間的元素不能和arr[i]相等,因為k和i之間的元素都是和k交換過的, //如果arr[i]和arr[k+1]--->arr[i-1]之間的元素有相等的,那么這兩種排列也是重復的 //下面代碼中||運算前的是第一種情況,或運算之后的是第二種情況 bool Appear(int index, char target, int begin, int end) {for (int i=begin; i<=end; ++i){if (target == pwd[index][i])return true; }return false; }void perm(int index, int k, int m) {//得到一種全排列 if (k == m) {//判斷在不在str中if (str.find(pwd[index]) != -1) {++count;}return;}//全排列for (int i=k; i<=m; ++i){//判斷字母是否重復if ((i!=k && pwd[index][i]==pwd[index][k]) || Appear(index, pwd[index][i], k+1, i-1))continue;swap(index, k, i);perm(index, k+1, m);swap(index, k, i); } }int main() {cin >> str;cin >> n;pwd = new string[n]; for (int i=0; i<n; ++i)cin >> pwd[i];for (int i=0; i<n; ++i){perm(i, 0, 7); }cout << count << endl;delete[] pwd; return 0; }

總結

以上是生活随笔為你收集整理的排列组合(两种方法)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。