`
frank-liu
  • 浏览: 1665334 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

排列组合生成问题的讨论(二)

 
阅读更多

简介

    在前面的文章里我们讨论了排列,全排列和可重复排列的几种实现。这里我们接着讨论组合的几种情况以及对应的实现。这些问题衍生出来的其他问题非常多,不过都有一定的套路可以遵循。这里针对这些情况一一讨论。

 

问题分析

    具体组合的情况也有不同种。比如说我们最常见的,针对不重复的n个元素的集合a,从其中取出k个元素来(k <= n), 所有取出这些元素和位置无关,所以它们构成一个组合C(n, k)。还有一些是针对可以重复的集合取出k个数的情况。另外,针对纯组合问题,我们可能会考虑一些针对集合元素里所有可能的组合,包括的元素个数从1个到n个。还有一些若干个元素之和等于某些元素的问题,也可以从这里找到相关的思路。

 

不可重复取组合

    针对这种情况,我们先来看一个示例,假设我们有数据集合{1, 2, 3},那么如果从里面取两个元素的组合则有(12), (13), (23)。其中每个元素只能在被选择的集合里出现一次。这里是假设我们原有的数据集合里也没有重复的元素。

    现在,我们来考虑一种实现组合的思路。以前面的数据集合{1, 2, 3}为例。首先,我们在目的数据集里取第一个元素1, 那么后面一个位置可以取的元素就是从{2, 3}里挑了。原来选定的1不能取。在前面的一个元素选择了之后,我们后面要选择或者能选择的范围应该被前面的给限定了。所以,如果我们用递归的函数来描述的话,必然有一个类似与槛一样的参数,它指定后面的元素只能从某个范围开始来取。以数列{1, 2, 3, 4, 5}为例来看。首先第一个位置取1, 然后第二个取2, 于是得到(12)。如果有第三个项的话,需要取的是3。后面可以取的是(124),(125)。所以,从这里可以看到,每个位置所取的元素是从前面指定位置后的所有可以取的位置。

    我们再考虑一下递归结束的条件。当递归的层次到给定取的元素个数时,才能输出给定的组合,并退出。

     于是,按照前面的这个思路,我们可以得到一个大致的伪码实现:

void combine(源数据集合a, 目的数据集合b, 当前迭代起始点begin, 当前目标数据集合位置cur, int n) {
    if(cur == n)
       //输出数组b
    for(集合a中间从begin到end的元素i) {
        b[cur] = a[i];
        combine(a, b, i + 1, cur + 1, n);
    }
}

   从这部分伪码来进一步细化一下代码实现。这里传递的begin其实就是从源数组里开始搜索的位置。于是,详细的实现如下:

public static void newCombine(int[] a, int[] b, int begin, int cur, int n) {
        if(cur == n) {
            printList(b);
            return;
        }
        for(int i = begin; i < a.length; i++) {
            b[cur] = a[i];
            newCombine(a, b, i + 1, cur + 1, n);
        }
    }

    我们需要注意的就是在实现里,if(cur == n)里设定了return语句。因为当这部分输出数组的工作结束就该返回了。我们也可以通过将后面的for循环包含在else语句中来省略掉return语句。调用这个函数的示例代码如下:

public static void main(String[] args) {
        int[] a = {1, 2, 3, 4};
        int n = 2;
        int[] b = new int[n];
        newCombine(a, b, 0, 0, n);
    }

 

可重复取组合

    假设源数组里有数字{1, 2, 3, 4},要求取两个数字的组合。那么可重复取的组合可以有(11), (12), (22)等。和前面取组合元素里一个最大的差异就是,前面的取法里要求后面能取的元素只能是前面给定的开始范围。而因为这里可以最小取一个和前面给定元素相同的。比如说当前元素所在的索引为i,那么后面需要取的元素只要是大于或者等于b[i - 1]的。这样,这种取法的一个特点就是不需要根据当前取到的元素去给后面的元素指定开始取的位置了。

    在原来的基础上,我们修改后的代码实现如下:

public static void repCombine(int[] a, int[] b, int cur, int n) {
        if(cur == n) {
            printList(b);
            return;
        }
        for(int i = 0; i < a.length; i++) {
            if(cur == 0 || a[i] >= b[cur - 1]) {
                b[cur] = a[i];
                repCombine(a, b, cur + 1, n);
            }
        }
    }

    这里的要点也在于这个if(cur == 0 || a[i] > b[cur - 1])这个判断。这里根据是否为开始的索引0或者判断取到的元素是否比前面已经取的元素大来确定下一个元素。相对来说,调用方法参数更少一些。调用的方法代码如下:

public static void main(String[] args) {
        int[] a = {1, 2, 3, 4};
        int n = 2;
        int[] b = new int[2];
        repCombine(a, b, 0, n);
    }

 

总结

    这里结合不能重复取和可以重复取的两种情形进行了分析。重点在于组合的选取里,我们首先保证源数据是有序的,这样每次取的元素可以根据顺序来判断获取。而后面取的元素基于一个递归迭代的关系,要么根据当前的位置来指定下一次搜索源数据的位置,要么按照一定的条件从源数据和当前目标数据列里进行判断筛选。思路比较有意思,值得好好体会。我们以前讨论过的部分排列其实用到了组合和排列技术的结合。它无非就是首先取得一个组合,然后再对组合的元素进行全排列。另外,本文前面提到的一些其他的应用也会在后续的文章里讨论。

 

参考材料

http://blog.csdn.net/zmazon/article/details/8315418

分享到:
评论

相关推荐

    中文版《计算机程序设计艺术》第四卷-第2册(双语版)生成所有元组和排列

    作为关于组合查找的一部分,《计算机程序设计艺术:生成所有元组和排列(第4卷)(第2册)(双语版)》开始关于如何生成所有可能性的讨论。 关于算法分析的这多卷论著已经长期被公认为经典计算机科学的定义性描述。...

    计算机要学哪些东西----(还有附赠哦)

    1. 计算一个集合的排列和组合,并解释在特定应用环境中的意义。 2. 阐述Master定理的定义。 3. 计算各种不同的递推式。 4. 分析问题,产生相应的递推式或识别重要的计算问题 DS5. 图和树 (核心) 主题: 树 ...

    word使用技巧大全

    二、使WORD里面的文章自动生成目录 1 (一) 设置标题格式 1 (二) 自动生成目录 1 (三) 更新目录的方法 2 三、自动生成目录图片演示 2 4.用标题1,2,3分别去定义文中的每一章节 4 四、如何自动生成目录? 6 五、奇偶...

    人力资源管理软件(完全免费)

    岗位管理处能否按公司排列显示(感谢蓝血人) 员工资料管理界面的公司和部门显示做了优化 人力资源管理软件奖励管理界面的公司和部门显示做了优化 培训管理界面的公司和部门显示做了优化 处罚管理界面的公司和部门...

    JAVA基础之java的移位运算

    在本例中,变量a与b对应位的组合代表了二进制数所有的 4 种组合模式:0-0,0-1,1-0 ,和1-1 。“|”运算符和“&”运算符分别对变量a与b各个对应位的运算得到了变量c和变量d的值。对变量e和f的赋值说明了“^”运算符...

    asp.net知识库

    直接从SQL语句问题贴子数据建表并生成建表语句的存储过程 从SQL中的一个表中导出HTML文件表格 获取數据库表的前N条记录 几段SQL Server语句和存储过程 生成表中的数据的脚本 最详细的SQL注入相关的命令整理 Oracle ...

    最好的asp CMS系统科讯CMSV7.0全功能SQL商业版,KesionCMS V7.0最新商业全能版-免费下载

    本系统是一款由文章、图片、下载、分类信息、商城、求职招聘、影视、动漫(flash)、音乐、广告系统、个人/企业空间、小型互动论坛、友情链接、公告、调查等20多个功能模块,并集成自定义模型、自定义字段等功能组合而...

    算法分析与设计习题集答案

    36、 (组合问题)求出从自然数1,2,…,n中任取r个数的所有组合。 37、 传教士与野人渡河问题。有M个传教士和M个野人准备渡河,船一次最多载2人,任何时刻野人数不能多于传教士数,但允许全部为野人。编写算法给出...

    LINGO软件的学习

    LINGO生成了三个父集的所有组合共八组作为allowed集的成员。列表如下: 编号 成员 1 (A,M,1) 2 (A,M,2) 3 (A,N,1) 4 (A,N,2) 5 (B,M,1) 6 (B,M,2) 7 (B,N,1) 8 (B,N,2) 成员列表被忽略时,派生集成员由父集...

    华东《计算机图形学》2017年春学期在线作业(一).doc

    任意一个变换序列均可表示为一个组合变换矩阵,该组合变换矩阵是基本变换矩阵的和 D. 旋转变换后各图形部分间的线性关系和角度关系不变,变换后直线的长度不变 正确答案: 3. 下列关于直线段扫描转换的中点算法中,〔 ...

    2009计算机 毕业设计 诚信体育用品

    厂商自动生成连接问题这个功能并不能算得上是一个模块,更准确地说是网上前台销售模块的一个功能。当有促销价时,结算是以促销价为准。如没有促销价,则以正常的价格为准。厂商自动生成链接功能,也是前台销售程序的...

    图像处理基础(第2版).[美]Maria Petrou(带详细书签).pdf

    3.3.5 当讨论鸡尾酒会问题时说“x1(t)的采样比s1(t)或s2(t)的采样更趋向于高斯分布”是什么含义?是谈论x1(t)的时间采样还是谈论在给定时间x1(t)的所有可能版本? 174 3.3.6 如何测量非高斯性? 177 3.3.7 如何...

    SQL语法大全

    SQL语法大全 SQL语法大全 1. ASP与Access数据库连接: dim conn,mdbfile mdbfile=server.mappath("数据库名称.mdb") set conn=server.createobject("adodb.connection") conn.open "driver={microsoft access ...

    软件界面设计工具_3款合集

    可使用标准Windows元素创建图形用户界面(GUI)屏幕,包括框架窗口、会话、菜单、工具栏、标签、按钮、复选框、单选按钮、滚动条、滑动调节框、微调框、组合框、树列表、列表框、编辑框以及静态文本等。 通过现有...

    oracle学习文档 笔记 全面 深刻 详细 通俗易懂 doc word格式 清晰 连接字符串

    认真听课、多思考问题、多动手操作、有问题一定要问、多参与讨论、多帮组同学 五、 体系结构 oracle的体系很庞大,要学习它,首先要了解oracle的框架。oracle的框架主要由物理结构、逻辑结构、内存分配、后台进程...

    多媒体教室

    语音讨论功能可以将全班学生分成同一个组或分成几个组进行课堂上的讨论,每个组相互不干扰。 文件提交功能可以收集学生所做的作业,方便老师操作。 电子点名功能方便老师统计学生上课考勤情况。 教师可通过视频...

    Linux操作系统基础教程

    第三讲 Linux下的网络服务,配置问题和常用工具.................................................................24 一.Linux下的网络服务.....................................................................

Global site tag (gtag.js) - Google Analytics