C++11 用next_permutation算法计算排列组合数

简介: C++11 用next_permutation算法计算排列组合数

自定义一个函数 size_t permuteVect (vector<string>&s, string t, size_t i=0, bool combine=false)

功能:对字串t任取其中的i个字符进行排列或组合,结果存入vector,返回值即排列组合数。

对于全排列就是使用next_permutation()做do-while循环的结果,对全排列函数的执行时间做了一下测试:


 阶乘数量级           排列耗时

 8!= 40320           0.4s

 9!= 362880         0.6s

10!= 3628800       3s

11!= 39916800     30s

12!= 479001600   200s后内存不足退出


部分排列就是把全排列结果截短排序再删除重复的即可,7个数任取几个的排列耗时在0.7秒左右,8个数耗时8~9s左右,9个或9个以上耗时太长没有意义。


组合就是在部分排列的基础上不考虑顺序的结果,7个数任取几个的组合耗时在0.8秒左右,8个数在10~20s之间,同样9个或9个以上耗时太长没有意义,时间都主要耗在了对36万以上个字串的排序上。

因此,本函数可以用于长度小于8的字串排列组合,全排列可以10位以内。源代码及测试结果,如下:


#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
#define print_test_msg {\
  cout<<s.size()<<"个数任取"<<i<<"个的"; \
  cout<<(combine?"组合":"排列")<<"有"<<j<<"种:"<<endl; \
    for (auto v:m) cout<<v<<" "; cout<<endl<<endl; \
}
size_t permuteVect(vector<string>&s, string t, size_t i=0, bool combine=false)
{ //对字串t任取其中的i个字符进行排列或组合,结果存入vector,返回值即排列组合数 
  s.clear();
  sort(t.begin(),t.end());
    if (combine&&(i==0||i>=t.size())){
        s.push_back(t);
        return 1;
    }
    if (i==1){
      reverse(t.begin(),t.end());
        while (t.size()) s.push_back(t.substr(t.size()-1,1)),t.pop_back();
        return s.size();
    }
  do s.push_back(i==0||i>=t.size()?t:t.substr(0,i));
      while (next_permutation(t.begin(),t.end()));
    if (combine) for (auto&y:s) sort(y.begin(),y.end());
    if (i>0){
        sort(s.begin(),s.end());
    for (auto r=s.begin();r<s.end()-1;r++)
      if (*r==*(r+1)) s.erase(r--); 
  }
    return s.size();
}
void test(void)
{
  string s="123456";
  size_t i,j;
    vector<string> m;
    bool combine;
    i=3; combine=true;
    j=permuteVect(m,s,i,combine);
  print_test_msg;
    i=3; combine=false;
    j=permuteVect(m,s,i,combine);
  print_test_msg;
    i=4; combine=true;
    j=permuteVect(m,s,i,1); //1==true
  print_test_msg;
    i=4; combine=false;
    j=permuteVect(m,s,i,0); //0==false
  print_test_msg;
    s.pop_back(); s.pop_back(); //字串s去掉后2个字符 
    i=3; combine=false;
    j=permuteVect(m,s,i); //缺省一个参数就是排列 
  print_test_msg;
    i=3; combine=true;
    j=permuteVect(m,s,i,true);
  print_test_msg;
    j=permuteVect(m,s); //缺省两个参数就是全排列 
  cout<<s.size()<<"个数的全排列有"<<j<<"种:"<<endl; 
    for (auto v:m) cout<<v<<" "; cout<<endl;   
}
int main(void)
{
  test();
  return 0;
}


测试结果:

6个数任取3个的组合有20种:
123 124 125 126 134 135 136 145 146 156 234 235 236 245 246 256 345 346 356 456
6个数任取3个的排列有120种:
123 124 125 126 132 134 135 136 142 143 145 146 152 153 154 156 162 163 164 165
213 214 215 216 231 234 235 236 241 243 245 246 251 253 254 256 261 263 264 265
312 314 315 316 321 324 325 326 341 342 345 346 351 352 354 356 361 362 364 365
412 413 415 416 421 423 425 426 431 432 435 436 451 452 453 456 461 462 463 465
512 513 514 516 521 523 524 526 531 532 534 536 541 542 543 546 561 562 563 564
612 613 614 615 621 623 624 625 631 632 634 635 641 642 643 645 651 652 653 654
6个数任取4个的组合有15种:
1234 1235 1236 1245 1246 1256 1345 1346 1356 1456 2345 2346 2356 2456 3456
6个数任取4个的排列有360种:
1234 1235 1236 1243 1245 1246 1253 1254 1256 1263 1264 1265 1324 1325 1326 1342
1345 1346 1352 1354 1356 1362 1364 1365 1423 1425 1426 1432 1435 1436 1452 1453
1456 1462 1463 1465 1523 1524 1526 1532 1534 1536 1542 1543 1546 1562 1563 1564
1623 1624 1625 1632 1634 1635 1642 1643 1645 1652 1653 1654 2134 2135 2136 2143
2145 2146 2153 2154 2156 2163 2164 2165 2314 2315 2316 2341 2345 2346 2351 2354
2356 2361 2364 2365 2413 2415 2416 2431 2435 2436 2451 2453 2456 2461 2463 2465
2513 2514 2516 2531 2534 2536 2541 2543 2546 2561 2563 2564 2613 2614 2615 2631
2634 2635 2641 2643 2645 2651 2653 2654 3124 3125 3126 3142 3145 3146 3152 3154
3156 3162 3164 3165 3214 3215 3216 3241 3245 3246 3251 3254 3256 3261 3264 3265
3412 3415 3416 3421 3425 3426 3451 3452 3456 3461 3462 3465 3512 3514 3516 3521
3524 3526 3541 3542 3546 3561 3562 3564 3612 3614 3615 3621 3624 3625 3641 3642
3645 3651 3652 3654 4123 4125 4126 4132 4135 4136 4152 4153 4156 4162 4163 4165
4213 4215 4216 4231 4235 4236 4251 4253 4256 4261 4263 4265 4312 4315 4316 4321
4325 4326 4351 4352 4356 4361 4362 4365 4512 4513 4516 4521 4523 4526 4531 4532
4536 4561 4562 4563 4612 4613 4615 4621 4623 4625 4631 4632 4635 4651 4652 4653
5123 5124 5126 5132 5134 5136 5142 5143 5146 5162 5163 5164 5213 5214 5216 5231
5234 5236 5241 5243 5246 5261 5263 5264 5312 5314 5316 5321 5324 5326 5341 5342
5346 5361 5362 5364 5412 5413 5416 5421 5423 5426 5431 5432 5436 5461 5462 5463
5612 5613 5614 5621 5623 5624 5631 5632 5634 5641 5642 5643 6123 6124 6125 6132
6134 6135 6142 6143 6145 6152 6153 6154 6213 6214 6215 6231 6234 6235 6241 6243
6245 6251 6253 6254 6312 6314 6315 6321 6324 6325 6341 6342 6345 6351 6352 6354
6412 6413 6415 6421 6423 6425 6431 6432 6435 6451 6452 6453 6512 6513 6514 6521
6523 6524 6531 6532 6534 6541 6542 6543
4个数任取3个的排列有24种:
123 124 132 134 142 143 213 214 231 234 241 243 312 314 321 324 341 342 412 413
421 423 431 432
4个数任取3个的组合有4种:
123 124 134 234
4个数的全排列有24种:
1234 1243 1324 1342 1423 1432 2134 2143 2314 2341 2413 2431 3124 3142 3214 3241
3412 3421 4123 4132 4213 4231 4312 4321
--------------------------------
Process exited after 0.4791 seconds with return value 0
请按任意键继续. . .



重复排列


比如从四个运算符+-*/中任取3个且可以重复取的排列数有:4x4x4=64,暂时没找到现成的库函数可以用,只有自己用多重循环来实现。

#include <iostream>
#include <iomanip>
#include <vector>
#include <array>
#include <string>
using namespace std;
void permuteSign(vector<string>&v)
{ //四个字符任取3个的重复排列 
  string t,s="+-*/";
  for (int i=0;i<s.size();i++)
    for (int j=0;j<s.size();j++)
      for (int k=0;k<s.size();k++){
        t.clear();
        t.push_back(s[i]);
        t.push_back(s[j]);
        t.push_back(s[k]);
        v.push_back(t);
      }
}
bool eliminateSign(string s)
{ //排除不想要的排列 
  array<string,14>signs{"---","///","//-","-//","/-/","//+",
              "+//","/+/","/--","-/-","--/","+--","-+-","--+"};
  for (auto a:signs) if (a==s) return true;
  return false;
}
int main(void) 
{
  int i=0;
  vector<string>vSgn;
  permuteSign(vSgn);
  cout<<"4种运算符中任取3种的可重复排列:"<<endl; 
  for (auto v:vSgn){
    cout<<v<<" ";
    if (++i%10==0) cout<<endl;
  }
  for (auto iter=vSgn.begin();iter!=vSgn.end();iter++)
    if (eliminateSign(*iter)) vSgn.erase(iter--); 
  i=0;
  cout<<"\n\n删除14种不符合要求的排列后:"<<endl; 
  for (auto v:vSgn){
    cout<<v<<" ";
    if (++i%10==0) cout<<endl;
  }
  return 0;
}


运行结果:

/*
4种运算符中任取3种的可重复排列:
+++ ++- ++* ++/ +-+ +-- +-* +-/ +*+ +*-
+** +*/ +/+ +/- +/* +// -++ -+- -+* -+/
--+ --- --* --/ -*+ -*- -** -*/ -/+ -/-
-/* -// *++ *+- *+* *+/ *-+ *-- *-* *-/
**+ **- *** **/ */+ */- */* *// /++ /+-
/+* /+/ /-+ /-- /-* /-/ /*+ /*- /** /*/
//+ //- //* ///
删除14种不符合要求的排列后:
+++ ++- ++* ++/ +-+ +-* +-/ +*+ +*- +**
+*/ +/+ +/- +/* -++ -+* -+/ --* -*+ -*-
-** -*/ -/+ -/* *++ *+- *+* *+/ *-+ *--
*-* *-/ **+ **- *** **/ */+ */- */* *//
/++ /+- /+* /-+ /-* /*+ /*- /** /*/ //*
--------------------------------
Process exited after 3.89 seconds with return value 0
请按任意键继续. . .
*/ 
目录
相关文章
|
1月前
|
算法 机器人
基于SOA海鸥优化算法的PID控制器最优控制参数计算matlab仿真
本课题研究基于海鸥优化算法(SOA)优化PID控制器参数的方法,通过MATLAB仿真对比传统PID控制效果。利用SOA算法优化PID的kp、ki、kd参数,以积分绝对误差(IAE)为适应度函数,提升系统响应速度与稳定性。仿真结果表明,SOA优化的PID控制器在阶跃响应和误差控制方面均优于传统方法,具有更快的收敛速度和更强的全局寻优能力,适用于复杂系统的参数整定。
|
5月前
|
存储 监控 算法
基于 C++ 哈希表算法实现局域网监控电脑屏幕的数据加速机制研究
企业网络安全与办公管理需求日益复杂的学术语境下,局域网监控电脑屏幕作为保障信息安全、规范员工操作的重要手段,已然成为网络安全领域的关键研究对象。其作用类似网络空间中的 “电子眼”,实时捕获每台电脑屏幕上的操作动态。然而,面对海量监控数据,实现高效数据存储与快速检索,已成为提升监控系统性能的核心挑战。本文聚焦于 C++ 语言中的哈希表算法,深入探究其如何成为局域网监控电脑屏幕数据处理的 “加速引擎”,并通过详尽的代码示例,展现其强大功能与应用价值。
131 2
|
6月前
|
存储 算法 C++
Windows共享文件:探秘C++实现的B树索引算法奇境
在数字化时代,Windows共享文件的高效管理至关重要。B树算法以其自平衡多路搜索特性,在文件索引与存储优化中表现出色。本文探讨B树在Windows共享文件中的应用,通过C++实现具体代码,展示其构建文件索引、优化数据存储的能力,提升文件检索效率。B树通过减少磁盘I/O操作,确保查询高效,为企业和个人提供流畅的文件共享体验。
|
5月前
|
算法 JavaScript 数据安全/隐私保护
基于GA遗传优化的最优阈值计算认知异构网络(CHN)能量检测算法matlab仿真
本内容介绍了一种基于GA遗传优化的阈值计算方法在认知异构网络(CHN)中的应用。通过Matlab2022a实现算法,完整代码含中文注释与操作视频。能量检测算法用于感知主用户信号,其性能依赖检测阈值。传统固定阈值方法易受噪声影响,而GA算法通过模拟生物进化,在复杂环境中自动优化阈值,提高频谱感知准确性,增强CHN的通信效率与资源利用率。预览效果无水印,核心程序部分展示,适合研究频谱感知与优化算法的学者参考。
|
3月前
|
存储 监控 算法
基于跳表数据结构的企业局域网监控异常连接实时检测 C++ 算法研究
跳表(Skip List)是一种基于概率的数据结构,适用于企业局域网监控中海量连接记录的高效处理。其通过多层索引机制实现快速查找、插入和删除操作,时间复杂度为 $O(\log n)$,优于链表和平衡树。跳表在异常连接识别、黑名单管理和历史记录溯源等场景中表现出色,具备实现简单、支持范围查询等优势,是企业网络监控中动态数据管理的理想选择。
106 0
|
4月前
|
存储 机器学习/深度学习 算法
基于 C++ 的局域网访问控制列表(ACL)实现及局域网限制上网软件算法研究
本文探讨局域网限制上网软件中访问控制列表(ACL)的应用,分析其通过规则匹配管理网络资源访问的核心机制。基于C++实现ACL算法原型,展示其灵活性与安全性。文中强调ACL在企业与教育场景下的重要作用,并提出性能优化及结合机器学习等未来研究方向。
123 4
|
5月前
|
监控 算法 数据处理
基于 C++ 的 KD 树算法在监控局域网屏幕中的理论剖析与工程实践研究
本文探讨了KD树在局域网屏幕监控中的应用,通过C++实现其构建与查询功能,显著提升多维数据处理效率。KD树作为一种二叉空间划分结构,适用于屏幕图像特征匹配、异常画面检测及数据压缩传输优化等场景。相比传统方法,基于KD树的方案检索效率提升2-3个数量级,但高维数据退化和动态更新等问题仍需进一步研究。未来可通过融合其他数据结构、引入深度学习及开发增量式更新算法等方式优化性能。
162 17
|
4月前
|
机器学习/深度学习 存储 算法
基于 C++ 布隆过滤器算法的局域网上网行为控制:URL 访问过滤的高效实现研究
本文探讨了一种基于布隆过滤器的局域网上网行为控制方法,旨在解决传统黑白名单机制在处理海量URL数据时存储与查询效率低的问题。通过C++实现URL访问过滤功能,实验表明该方法可将内存占用降至传统方案的八分之一,查询速度提升约40%,假阳性率可控。研究为优化企业网络管理提供了新思路,并提出结合机器学习、改进哈希函数及分布式协同等未来优化方向。
109 0
|
6月前
|
存储 监控 算法
基于 C++ 哈希表算法的局域网如何监控电脑技术解析
当代数字化办公与生活环境中,局域网的广泛应用极大地提升了信息交互的效率与便捷性。然而,出于网络安全管理、资源合理分配以及合规性要求等多方面的考量,对局域网内计算机进行有效监控成为一项至关重要的任务。实现局域网内计算机监控,涉及多种数据结构与算法的运用。本文聚焦于 C++ 编程语言中的哈希表算法,深入探讨其在局域网计算机监控场景中的应用,并通过详尽的代码示例进行阐释。
126 4
|
7月前
|
存储 算法 安全
企业员工数据泄露防范策略:基于 C++ 语言的布隆过滤器算法剖析[如何防止员工泄密]
企业运营过程中,防范员工泄密是信息安全领域的核心议题。员工泄密可能致使企业核心数据、商业机密等关键资产的流失,进而给企业造成严重损失。为应对这一挑战,借助恰当的数据结构与算法成为强化信息防护的有效路径。本文专注于 C++ 语言中的布隆过滤器算法,深入探究其在防范员工泄密场景中的应用。
135 8

热门文章

最新文章