zoukankan      html  css  js  c++  java
  • 排列组合【转】

    (1) 全排列:

    将数组看为一个集合,将集合分为两部分:0~s和s~e,其中0~s表示已经选出来的元素,而s~e表示还没有选择的元素。

    perm(set, s, e)

    {

    顺序从s~e中选出一个元素与s交换(即选出一个元素)

    调用perm(set, s + 1, e)

    直到s>e,即剩余集合已经为空了,输出set

    }

     1 void perm(int list[], int s, int e, void (*cbk)(int list[])) 
     2 {     
     3     int i;
     4     if(s > e)     
     5     {
     6         (*cbk)(list);
     7     }
     8     else    
     9     {         
    10         for(i = s; i <= e; i++)
    11         {             
    12              swap(list, s, i);             
    13              perm(list, s + 1, e, cbk);             
    14              swap(list, s, i);         
    15         }
    16     }
    17 }

    排列的非递归算法:

    L算法作用于有序序列a_1 < a_2 < a_3 < ... < a_n 上(可以改写成≤的形式),其算法步骤如下:

    1. 输出序列本身
    2. 从右至左找到第一个a_j,使得a_j < a_{j+1}且a_{j+1} > a_{j+2} > ... > a_n
    3. 在a[j+1..n]中找到最小的a_k使得a_j < a_k,交换a_j和a_k
    4. 将a[j+1..n]逆序,输出当前序列
    5. 重复第2~5步,直到找不到第二步中合适的a_j

    这种算法可以生成字典序的排列序列。

     1 public static IEnumerable<T[]> FullPermutations<T>(IEnumerable<T> iter) where T : IComparable<T>
     2 {
     3     var pool = iter.ToArray();
     4     while (true)
     5     {
     6         yield return pool.ToArray();
     7         int j = pool.Length - 2;
     8         while (j >= 0 && pool[j].CompareTo(pool[j + 1]) >= 0)
     9         {
    10             j--;
    11         }
    12         if (j < 0)
    13             yield break;
    14         int k = pool.Length - 1;
    15         while (k > j && pool[k].CompareTo(pool[j]) <= 0)
    16         {
    17             k--;
    18         }
    19         SwapItem(pool, j, k);
    20         Reverse(pool, j + 1, pool.Length - 1);
    21     }
    22 }
    23 private static void Reverse<T>(IList<T> lst, int s, int e)
    24 {
    25     while (s < e)
    26     {
    27         Swap(lst, s, e);
    28         s++;
    29         e--;
    30     }
    31 }

    (2)组合

    组合指从n个不同元素中取出m个元素来合成的一个组,这个组内元素没有顺序。使用C(n, k)表示从n个元素中取出k个元素的取法数。

    每一次从集合中选出一个元素,然后对剩余的集合(n-1)进行一次k-1组合。反向地选取。

     1 class Solution {
     2 public:
     3     vector<vector<int> > combine(int n, int k) {
     4         vector<int> r(k, 0);
     5         recursive(n, k, r);
     6         return ret;
     7     }
     8     
     9     void recursive(int n, int k, vector<int> &r) {
    10         if (k <= 0) {
    11             ret.push_back(r);
    12             return;
    13         }
    14         for (int i = n; i >= k; --i) {
    15             r[k - 1] = i;
    16             recursive(i - 1, k - 1, r);
    17         }
    18     }
    19     
    20 private:
    21     vector<vector<int> > ret;
    22 };

     组合的非递归实现:

    首先初始化,将数组前n个元素置1,表示第一个组合为前n个数。     
    然后从左到右扫描数组元素值的“10”组合,找到第一个“10”组合后将其变为   
    “01”组合,同时将其左边的所有“1”全部移动到数组的最左端。     
    当第一个“1”移动到数组的m-n的位置,即n个“1”全部移动到最右端时,就得   
    到了最后一个组合。     
      例如求5中选3的组合:     
      1   1   1   0   0   //1,2,3     
      1   1   0   1   0   //1,2,4     
      1   0   1   1   0   //1,3,4     
      0   1   1   1   0   //2,3,4     
      1   1   0   0   1   //1,2,5     
      1   0   1   0   1   //1,3,5     
      0   1   1   0   1   //2,3,5     
      1   0   0   1   1   //1,4,5     
      0   1   0   1   1   //2,4,5     
      0   0   1   1   1   //3,4,5  

  • 相关阅读:
    反射学习系列3反射实例应用
    (转)华为牛人在华为工作十年的感悟!
    利用日志记录所有LINQ的增,删,改解决方案
    qt5摄像头
    opencvcartToPolar笛卡尔坐标转极坐标
    逆矩阵
    方阵的行列式
    qt5右键菜单
    矩阵的转置
    opencvpyrDown降采样和pyrUp升采样
  • 原文地址:https://www.cnblogs.com/linyx/p/3651984.html
Copyright © 2011-2022 走看看