如何遍历组合数?(不是求组合数,含代码)
1、遍历组合数的方法原理
组合数是高中代数的知识,这里我就不废话了。
这里讨论的是如何遍历组合数。举个例子,一个电影院里面,有十个座位和8个客人,到底有多少种坐法?(不考虑客人之间的相互位置。)高中组合数的知识告诉我们答案是C = 10 * 9 / 1 * 2 = 45种。
多少种坐法现在我们知道了,现在我们来考虑另外一个变态一点的问题,能不能把45种坐法都罗列出来。
这里给每个座位都编个号(假设第一个座位编号为0),这样就可以列举一些可能的坐法出来:
0 1 2 3 4 5 6 7 8
0 1 2 3 4 5 6 7 9
0 1 2 3 4 5 6 8 9
0 1 2 3 4 5 7 8 9
0 1 2 3 4 6 7 8 9
............
上面的例子来说,对于一般人来说可能还不是很困难,反正也就是45个而已嘛,一个个数总可以数出来。但如果改变题法,比如,50个座位坐5个客人,这样的组合数就达到百万级了,这样的任务对于人来说就已经很困难。
因为组合数的增长速度近似于是指数级的增长,所以靠人肉眼去数是绝对数不过来的,那靠计算机能否实现呢?当然能。不过这需要用到一些数学上面的小技巧。下面的定理给出了这种遍历方法的数学原理。
定理1 设由n个正整数组成的整数集S里,存在着一个固定长度l的有序数列A {},则由所有满足这种关系的序列所组成的序列集{
},就是S关于l的所有组合。
证明:证明该定理,核心是证明是否所有可能的组合情况都能通过序列A的形式表现出来。
(反证法)假设存在着一种整数组合B不满足A的条件,现设,互换这两个数的位置,仍可以使第k位和第k+1位满足约束关系。但互换这两个位置后,原来的次序大小关系可能会被打破。但因为组成B的数都是正整数,根据自然数的良序关系,通过在B内进行位置的互换,总能找到一个子序列B'使
。因此通过对B内的数字进行位置互换,总有一个办法使B满足A的约束条件。这与假设矛盾,命题成立。
简而言之,就是在整数集内任意取l个值,总能取出一个按序递增(减)的数列。这听起来像废话,但结论却很重要。这给出了一个在工程上遍历所有组合情况的思路。
2、算法步骤
- 以由小(大)到大(小)的顺序按最小步长依次初始化数组的各个元素。其中数组的第一个元素为数集的最小(大)元素。
- 从数组最后一位开始加(减)最小步长
- 当最后一位遇到溢出(溢出的阀值由整数集的大小确定)时,向前(向后)进位。
- 若前(后)一位也继续溢出时,继续向前(后)进位,直至不再溢出,或已经溢出到最前一位,算法结束。
- 输出数组的值,然后继续执行2直至算法结束。
下面证明该算法能遍历所有可能的整数组合。
证明:如果将数组看成是一个n进制数,那么数组的每一位元素就相当于各个数位上的值。因为初始化的时候是以从小到大的顺序排列,且最高位为数集中最小的数字S0。所以初始化时构造出的数值(假设为Xmin)必定是最小的。现在按最小步长增加数组的数值,在数组长度有限和可取数字有限的情况下,必定能取遍(Xmin,Xmax)所有的数字组合。
现假设某个数字组合B不能透过上述算法取得,那么这个数字组合对应的n进制数Vb要么大于Xmax,要么小于Xmin。
先考虑Vb < Xmin的情况,Vb < Xmin,意味着在Vb某个高位上存在着一个整数值v 小于Xmin对应位置的值。我们对数值上的所有位从高到低来进行讨论(因为如果低位数值大,但高位数值小,实际的数值也是比原来小)由于最高位数值已经是最小值,不能再小,所以,只能选择次高位。但次高位除非取最小值S0,否则,无法达到比Xmin小的效果。但一旦取S0,组合B就不再是组合数,与原来的题设矛盾。同样的讨论可以继续进行,对后面各位的讨论会发现,除非取前面相同的数字,否则无法找到另外一个数能使Vb < Xmin。因此Vb 一定不小于Xmin.
再来讨论Vb > Xmax的情况,由于讨论最大值的情况也是相似,可以发现每一位,除非取后面相同的值,否则没法达到Vb > Vmax的效果。
由此,可以明确地知道该算法的确能遍历所有组合数。
3、遍历算法的意义
由于组合数的增长是很可观的,即便计算机硬件技术发展到今天,恐怕也没有哪个程序会去求解所有排列组合情况。遍历算法的意义在于,可以在不需要考虑所有排列组合的情况下,挑出心目中最满意的组合。
还是举上面那个例子,假设每个客人对座位的要求都是挑剔的,如果你是电影院的老板,如果随意给他们编座位,可能马上就收到差评。但是也不可能罗列所有的情况让他们自己去挑。因为50个座位给5个人去挑就已经有差不多几百万种情况。因此可能的方案,是随机挑其中的几种给他们去选。但随机取出来的东西,又不能重复,否则程序就会出现死循环。因此最好的方案,就是把每种情况变成一个数值,通过数值的变化,来实现方案的永不重复。(当然现实生活中,最好的方案,就是由客人自己去挑自己心仪的座位,而不是编好位让他们去选。)
总括而言,遍历算法的意义,在于对一些涉及到排列组合的问题上,能快速寻找到下一个组合情况,并能通过存储组合的数字值来代替存储组合本身,节省计算机资源。
如何遍历组合数?(不是求组合数,含代码)相关推荐
- 算法 - 数学 - 组合数 - 隔板法求组合数
一.求组合数 二.隔板法 隔板法是組合數學的方法,用來處理n個無差別的球放進k個不同的盒子的問題.可一般化為求不定方程的解數,並利用母函數解決問題. 隔板法與插空法的原理一樣. 应用隔板法必须满足3个 ...
- c 语言 组合数,C++中求组合数的各种方法总结详解
[问题] 组合问题 问题描述:找出从自然数1.2.... .n中任取r个数的所有组合.例如n=5,r=3的所有组合为: 1,2,3 1,2,4 1,3,4 2,3,4 1,2,5 1,3,5 ...
- [AcWing]885. 求组合数 I(C++实现)求组合数模板题
[AcWing]885. 求组合数 I(C++实现)求组合数第一种题型模板题 1. 题目 2. 读题(需要重点注意的东西) 3. 解法 4. 可能有帮助的前置习题 5. 所用到的数据结构与算法思想 6 ...
- 算法刷题-数论-组合数、快速幂、逆元、递推求组合数、逆元求组合数
文章目录 acwing885. 求组合数 I(递推:数据范围:2000) acwing875. 快速幂(a的k次方 模 b) acwing876. 快速幂求逆元 acwing886. 求组合数 II( ...
- java实现n选m组合数_求组合数m_n
下面为求取组合数的代码: 1 #include #define MAX 10009 int prime[168]; void print(int *v, int length) { int i = 0 ...
- 求组合数(不同类型的组合数C++)
求组合数有许多种不同的算法,要根据不同的数据量大小选择不同的算法 类型1 给定 n 组询问,每组询问给定两个整数 a,b,请你输出 Cba mod(109+7)的值. 输入格式 第一行包含整数 n. ...
- Codeforces Round #361 (Div. 2) E. Mike and Geometry Problem 【逆元求组合数 离散化】
任意门:http://codeforces.com/contest/689/problem/E E. Mike and Geometry Problem time limit per test 3 s ...
- 1100: 求组合数(函数专题)
1100: 求组合数(函数专题) 时间限制: 1 Sec 内存限制: 128 MB 提交: 6264 解决: 4653 [提交] [状态] [讨论版] [命题人:admin] 题目描述 马上要举办新生 ...
- ZZULIOJ 1100: 求组合数(函数专题)
求组合数(函数专题) 题目描述 马上要举办新生程序设计竞赛了,与以往不同的是,本次比赛以班为单位,为了全面衡量一个班级的整体水平,要求从一个班的m位同学中任选k位同学代表本班参加比赛,问有多少种组合方 ...
最新文章
- tensor和模型 保存与加载 PyTorch
- Android Splash界面支持用户点击 直接进入主界面
- 国家五部委联合发布“AI标准顶层设计”:2021年明确、2023年初步建成
- 如何保证MongoDB的安全性?
- 技术人生:如何成为一位优秀的程序员
- Dockerfile基本结构
- iec61850采样协议(9-1、9-2)解析(二)
- sas ondemand for academics使用
- acl在内核里的位置_Linux 进程在内核眼中是什么样子的?
- Linux基础学习导图
- python中for循环-python中关于for循环的碎碎念
- 【OJ1768】最大子矩阵
- MyEclipse提示Errors occurred during the build
- 1120 Friend Numbers
- 建立一个mysql 文件命令是_使用命令行创建数据库
- c语言程序文件夹里没看到prj,求教。如何调用编好的函数。如何使用prj文件
- ✨❤️CSDN标题党❤️,创意无极限,那不直接全网站都花的飞起?
- Android:SQLite和AlertDialog
- 【Arcgis】图层的置顶与置底
- 用jQuery访问指定元素的父元素