使用回溯法求所有从n个元素中取m个元素的组合
来源:互联网 发布:淘宝花花家是正品吗 编辑:程序博客网 时间:2024/04/27 17:37
包含2个版本,第一个为递归版本,代码简洁,性能稍差。第二个为迭代版本,逻辑复杂,但性能更好。
#include <stdlib.h>#include <stdio.h>//#include <windows.h>typedef char ELE_TYPE;#define ELE_FMT "%c"//int g_count=0;//元素类型和格式符号使用宏定义,很容易改为其他数据类型,如数组类型改为int,则格式符改为"%d ".void printCombo(int idx_arr[], ELE_TYPE eArr[],int m){ int i;//g_count++;//return ;for (i=0;i<m;i++) printf(ELE_FMT,eArr[idx_arr[i]]); printf("\n");}// 递归形式的求组合数的函数combos,使用回溯法,求从n个元素中取m个元素的所有组合// 取到元素的序号保存在数组idx_arr[]中,以递增方式排列,每个序号的范围为从0到n-1// level为递归深度,取值范围为0到m-1,当level==m-1时, 所有的m个元素已经取到,打印这m个元素void combos(int n, int m, int idx_arr[], ELE_TYPE eArr[], int level ){ int i,begin,end; if (level==0) begin=0; else begin=idx_arr[level-1]+1; end=n-m+level; for (i=begin;i<=end;i++) { idx_arr[level]=i; if ( level==m-1) printCombo(idx_arr,eArr,m);//打印这m个个元素 else combos(n,m,idx_arr,eArr,level+1); //继续取一个元素 }}// 迭代形式的求组合数的子程序,该函数用于求n个元素中取m个元素的所有组合// 取到元素的序号保存在数组idx_arr[]中,以递增方式排列,每个序号的范围为从0到n-1// 其算法实质是不断地生成一个又一个的组合数,每次迭代对idx_arr中某个元素做更新操作// 在该子程序中,2个重要的变量mode和i用于控制更新操作,// mode表示更新模式,其值为M_FILL或者M_INC。// M_FILL表示填充模式,当mode为此模式,元素idx_arr[i]的值总是被设置为比上级元素idx_arr[i-1]大1的数// M_INC 表示增量模式,当mode为此模式,元素idx_arr[i]的值总是递增1个单位//关于“超限”,对于从n个元素中任取m个元素,取到的每个元素的序号是0到n-1// 我们把取到的元素的序号按照增序排列,存入idx_arr数组// 例,当n=5,m=3时,如果取到的最后一个元素的序号大于4,或者取到的倒数第2个元素大于3,我们称之为超限。// 更一般的,取到的idx_arr[i] > n-m+i,则为超限// 这个子程序用到5个if和一个while,总共6次比较,显然,其逻辑要比上面的那个递归版本复杂的多。// 凡事有利就有弊,这个子程序的性能要比上面的递归版本好,// 我的试验表明,将输出子程序printCombo改为只做一次整数加法,当n=28,m=14,迭代版本的性能是递归版本的130%#define M_FILL 0 //填充模式#define M_INC 1 //递增模式void IterativeCombos(int n, int m, int idx_arr[], ELE_TYPE eArr[] ){int i=0; int mode=M_FILL;while (i>=0){if (mode==M_FILL)//填充模式{if (i==0)idx_arr[0]=0;elseidx_arr[i] = idx_arr[i-1]+1;if (i == m-1)//当前焦点已经达到最大深度{printCombo(idx_arr,eArr,m); //打印这个包含m个元素的组合mode=M_INC;//切换为增量模式}else//没有达到最大深度i++;//继续填充下级节点}else//增量模式{idx_arr[i]++;//焦点元素递增if ( idx_arr[i] > n-m+i ) //已经超限i--;else{if (i==m-1)//当前焦点已经达到最大深度printCombo(idx_arr,eArr,m); //打印这个包含m个元素的组合else{i++; //继续填充下级节点mode=M_FILL; //切换到填充模式}}}}}int main(int argc, char* argv[]){ int i;#define N 6#define M 3 ELE_TYPE eArr[N]; //定义6个数组的数组, int idx_arr[M]; //取到的3个元素的需要放在数组idx_arr中for (i=0;i<sizeof(eArr)/sizeof(ELE_TYPE);i++) //数组的元素为'A'到'F' eArr[i]='A'+i;combos(sizeof(eArr)/sizeof(ELE_TYPE),M,idx_arr, eArr, 0); //枚举所有6中取3的组合IterativeCombos(sizeof(eArr)/sizeof(ELE_TYPE),M,idx_arr, eArr); //枚举所有6中取3的组合 return 0;}
- 使用回溯法求所有从n个元素中取m个元素的组合
- java实现从M个元素中取N个元素的所有组合(数学中的组合问题)
- N个元素中取M个的全组合
- 从长度为N的数组中找出所有M个元素组合的优化算法
- n个元素中取m个元素的组合、排列问题
- 求m个元素集合中n个元素的所有子集(C/OC)
- 从m中取n个元素-抽牌算法
- 求从1,2...n中取任意个不重复的数和为m的所有组合
- 如何求从n个元素中取出p个元素的组合总数,并把这些组合全部列出
- 求从n个数组任意选取一个元素的所有组合
- 算法题:求从n个数组任意选取一个元素的所有组合
- 从m个不定长数组中 各取一个元素的组合生成算法
- n个元素求m个最大的元素
- 从数组中取出n个元素的所有组合(递归实现)
- 从数组中取出n个元素的所有组合(递归实现)
- 从数组中取出n个元素的所有组合(递归实现)
- 从数组中取出n个元素的所有组合(递归实现)
- 从数组中取出n个元素的所有组合(递归实现)
- 通俗易懂解释java反射机制(一)
- hdu1087(上升子序列的最大和)
- 【python】多进程锁multiprocess.Lock
- 字符串一共占多少位(屏幕上) (包括中文,全角,半角,字母)
- 如何在自己的板子上实现android关机
- 使用回溯法求所有从n个元素中取m个元素的组合
- 如何查看端口被什么程序占用
- 文本输入框实时统计字数,并防止重复提交
- Windows下更换用户身份访问Samba服务器
- TCP/IP三次握手详解
- 第一篇文章
- Linux中link,unlink,close,fclose详解
- 【代码】Android: 怎样设置app不被系统k掉
- 深入理解linux互斥锁(mutex)