算法-递归法实现排列组合C++

根据维基百科上的介绍,排列(permutation)是将相异物体根据确定的顺序重排,每一种顺序都是一个排列。而组合(combination)较排列的区别是,组合不考虑排序顺序,当两个集合中元素相等,则视为同一种方式。

计算方式

排列:
P = A n m = n ! ( n − m ) ! P = A_n^m = \frac{n!}{(n-m)!} P=Anm=(nm)!n!

组合:
P = C n m = n ! m ! ( n − m ) ! P = C_n^m = \frac{n!}{m!(n-m)!} P=Cnm=m!(nm)!n!

应用

比赛赛程排列:如田忌赛马。

自然语言处理文字清洗。

C++代码实现排列

/** permutaion: 排列。
 * 从n个数中选出m个数的方式,若不考虑顺序Cn(m),若考虑顺序An(m)
 *//* 问题:密码破解
 * 假设有一个 4 位字母密码,每位密码是 a~e 之间的小写字。
 * 编写代码暴力破解密码。
 * 提示:根据可重复排列的规律,生成所有可能的 4 位密码。
 */

#include <iostream>
#include <vector>

using namespace std;
class Permutation {  
  private:  
    int resultCount_ = 0;  
  public:
  /** Details: 根据输入字母列表,获得所有的排列方式。
   *  params: result- 当前排列形式, candidate- 未排列字母表。
   *  return: null
   */
  void breakPassword(vector<string> result, vector<string> candidate) {    
    int len = candidate.size();    
    if (0 == len) {      
    // 无字母剩余,输出排列结果
      outputResult(result);
      resultCount_++;      
      return;
    }    
    for (int i = 0; i < len; i++) {      
      vector<string> resultNew;
      vector<string> candidateLeft;
      // 读取排列字母
      resultNew = result;
      resultNew.push_back(candidate[i]);      
      // 获得剩余字母表
      candidateLeft = candidate;   
      vector<string>::iterator it = candidateLeft.begin();
      candidateLeft.erase(it + i);      
      // 递归
      breakPassword(resultNew, candidateLeft);
    }
  }  
  // 输出结果  
  void outputResult(vector<string> result) {    
    for (unsigned int i = 0; i < result.size(); i++) {
      cout << result[i];
    }    
    cout << endl;
  }  
  // 获得所有可能密码总数    
  int getResultCount() {    
    return resultCount_;
  }
};
  int main(void) {  
    vector<string> fourAlphabetString = {"a", "b", "c", "d", "e"};  
    vector<string> res;
    Permutation test;
    test.breakPassword(res, fourAlphabetString);  
    cout << "可能的密码形式:";  
    cout << test.getResultCount() << "种" << endl;
  }

C++代码实现组合

#include <cmath>
#include <iostream>
#include <vector>
using namespace std;
// 组合
// 思想:从一些对象n中选出一部分m(1<=m<=n),不考虑顺序,可能的形式有几种。
// 应用:队伍参赛排序。自然语言处理中,处理输入词。当输入词相同仅顺序不一致时,
// 可以采用组合的概念将其排序,并认定为意思相同。

template<typename T> class Combination {  
private:  
  const int firstPrize;  
  const int secondPrize;  
  const int thirdPrize;  
public:
  Combination(int x, int y, int z)
      : firstPrize(x), secondPrize(y), thirdPrize(z) {
  }  
  /**
  * @description:
  * 从10个人中选出三等奖3人,二等奖2人,一等奖1人,不能重复获奖。
  * @param {type} rewardNum- 指定赏金数, result- 奖赏方式结果。
  * @return: null
  */
  void rewardMethods(vector<T> result, vector<T> candidate){    
    unsigned int len = thirdPrize + secondPrize + firstPrize;    
    if (result.size() == len) {      
      // 输出结果
      resultOutput(result);      
      return;
    } else {      
      for (unsigned int i = 0; i < candidate.size(); i++) {
        vector<int> resultNew = result;
        resultNew.push_back(candidate[i]); 
        vector<int> candidateNew;
        copyElem(candidate, candidateNew, i + 1);
        rewardMethods(resultNew, candidateNew);
      }
    }
  }  
  // 数据复制函数
  void copyElem(vector<T>& input, vector<T>& output, int i){    
    vector<int>::iterator it = input.begin() + i;    
    for (; it < input.end(); it++) {
      output.push_back(*it);
    }
  }  
  // 输出结果
  void resultOutput(vector<T> res) {    
    for (unsigned int i = 0; i < res.size(); i++) {      
      if (i == thirdPrize) cout << '*';     
      if (i == thirdPrize + secondPrize) 
      cout << '*';      
      cout << res[i] << ' ';
    }    
    cout << endl;
  }
};
  // test
  int main(void) {
    Combination <int> test(1, 2, 3);  
    vector<int> res;  vector<int> candidate;  
    // 输入
    for (unsigned int i = 0; i < 10; i++) {
      candidate.push_back(i + 1);
    }
    test.rewardMethods(res, candidate);
  }

更多内容,可关注公众号:青椒小记
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值