排列组合知多少--组合篇
来源:互联网 发布:win7网络图标不显示 编辑:程序博客网 时间:2024/05/22 07:44
这是我的第一篇博文,笔者资历尚浅,不对之处有劳斧正。算法之于程序,同如灵魂之于肉体,灵魂驾驭肉体,算法主宰程序,一点也不浮夸。学好算法,好比行走江湖有一技榜身;相反忽视算法,“问题”就多了,难求一解,效率低下之类,自不必说。受限于此,更是难以脱颖于同行,驻足于尖端。“码农”一说,由此得来。
切入正题,此篇主要分享3种不同的求组合算法(c++)
方法1 递归:
以一组数列为例:
1 2 3 4 5 中取3个数的组合,即n=5,r=3
组合规律如下:
首先固定第一个数为5,其后就是求解 n=4, r=2的组合数,共6个组合
其次固定第一个数为4,其后就是求解 n=3, r=2的组合数,共3个组合
最后固定第一个数为3,其后就是求解 n=2, r=2的组合数,共1个组合
这就找到了n=5,r=3与n=4,r=2,n=3,r=2,以及n=2,r=2的递归关系。
N个数中r个数组合递推到n-1,r-1;n-2,r-1;…r-1,r-1共n-r+1次递归。
递归停止条件是r=1.
#include "iostream.h"int a[100];void comb(int m,int k){int i,j;for(i=m;i>=k;i--){ a[k]=i; if(k>1) comb(i-1,k-1); else { for(j=a[0];j>0;j--) cout<<a[j]; cout<<endl; } }}void main(){ intn=5,r=3; a[0]=r; comb(n,r); }
方法2:非递归
通过while循环控制机制,采用回溯法的算法思想,实现非递归的组合算法。
以m=5,r=3为例。
数列0,1,2,3,4
第一个组合即为初始化的0,1,2,用数组a[100]的a[0],a[1],a[2]存储。 a[cur]标志当前控制的是a[0],a[1],a[2]中的哪一个(初始选择最后一个,即为a[2]).通过a[cur]-cur<=m-r可以判断是否越界。比如:若a[cur]为a[2]时,当a[2]取3,3-2<=5-3 故没越界,此刻组合为0,1,3;当a[2]取5时,5-2>5-3,组合输出为0,1,5很显然5根本取不到,故越界。
若不满足a[cur]-cur<=m-r ,那么执行a[--cur]++,回溯到上一层,a[cur]由a[2]变为a[1],同时a[1]=1变为a[1]=2,a[2]则变为3,组合即为0,2,3.若此时满足a[cur]-cur<m-r,表示还有数列还有空间,cur=r-1,即a[cur]由a[1]变为a[2]继续循环。不满足,则继续执行循环,下次a[cur]将回溯到a[0]。
#include "iostream.h"int a[100];void comb(int m,int r){ int cur; for(int i=0;i<r;i++) a[i]=i; cur=r-1; do{ if (a[cur]-cur<=m-r ){ for (int j=0;j<r;j++) cout<<a[j] <<" "; cout<<endl; a[cur]++; continue; } else{ if (cur==0){ break; } a[--cur]++; for(int i=1;i<r-cur;i++){ a[cur+i]=a[cur]+i; } if(a[cur]-cur<m-r) cur=r-1; } } while (1);}void main (){ int n;cin>>n;comb(n,i); }
递归的方法一般可读性强,代码量较小,设计难度小,使用范围广,但占用空间大,时间复杂度大(即耗时长)。而非递归的方法一般空间,时间效率都高,但可读性差,适用范围小且设计难度大。
但在强调软件维护优先于软件效率的今天,除了少数像求阶层和斐波那契数列那样的尾递归程序,其他需要设置栈才能转换为非递归的程序就没有转换非递归的必要。(此结论参考算法设计与分析第2版)
方法3:for循环解决法
以n=5,r=3为例,所有组合如下:
1 2 3
1 2 4
1 2 5
1 3 4
1 3 5
1 4 5
2 3 4
2 3 5
2 4 5
3 4 5
运用我们找规律的逻辑能力,不难发现这些组合满足两个特点:1.各不相同 2.前面的数小于后面的数。所以算法设计如下:
#include “iostream.h”void main(){int n=5,i,j,k;for(i=1;i<=n;i++)for(j=1;j<=n;j++)for(k=1;k<=n;k++)if(i<j&&j<k){t=t+1;cout<<i<<” ”<<j<<””<<k<<endl;}}
此方法代码最少,但因for循环机制的局限性,不能实现n,r的通用求法。
组合问题是一个经典不衰的问题,求解方法当然不止这些,例如2进制表示法,子集数搜索法之类会在子集数专栏介绍。最后,我的博文分享就此开始,作此以助人,同时也自勉,愿中国软件开发联盟越走越远。
- 排列组合知多少--组合篇
- 排列组合知多少--排列篇
- 排列组合------组合篇
- 递归求排列组合-组合篇
- 字符串排序组合 字符串”qiniu”根据顺序不同有多少种排列组合的方式?
- 组合数学->排列组合
- hdu 1521 排列组合 组合
- 组合数学-排列组合整理
- lua实现字母可重复组合有多少种(不可重复的看前面文章排列组合)
- 算法_3 : 组合数学:排列组合
- 排列组合_组合_数学公式
- 秒杀排列组合(下)————组合篇
- 秒杀排列组合(下)————组合篇
- 秒杀排列组合(下)————组合篇
- 排列组合之组合问题算法实现
- 组合数学之排列组合若干题
- hdu 4465 Candy 组合数(快速排列组合)
- [ACM] hdu 1521 排列组合(组合+DFS)
- VB.Net中创建AlphaForm窗体的源码
- javascript_javascript中的反射和映射
- Hadoop Distributed Cache 共享archives时的问题(以MapFile的共享为例)
- 错误 40 在应用程序级别之外使用注册为 allowDefinition='MachineToApplication' 的节是错误的。
- android的布局水平与垂直显示
- 排列组合知多少--组合篇
- CSDN博客图片显示测试
- 网络中硬件设备简介
- ubuntu下安装vsftpd及简要配置
- 正式离开CSDN博客
- SDRAM读写
- web.xml 中的listener、 filter、servlet 加载顺序及其详解
- 回顾与展望
- LED走马灯闪烁