c语言排列组合算法 数字怎么组合呢?

第6章全国计算机等级考试二级C语言 函数与编译预处理_百度文库
两大类热门资源免费畅读
续费一年阅读会员,立省24元!
评价文档:
喜欢此文档的还喜欢
第6章全国计算机等级考试二级C语言 函数与编译预处理
c​语​言
阅读已结束,如果下载本文需要使用
想免费下载本文?
把文档贴到Blog、BBS或个人站等:
普通尺寸(450*500pix)
较大尺寸(630*500pix)
你可能喜欢页面导航:
→ 正文内容 排列组合问题的通用算法
C语言实现的排列组合问题的通用算法、解决方法
这篇文章主要介绍了C语言实现的排列组合问题的通用算法、解决方法,本文使用C语言实现在程序中解决这个问题,需要的朋友可以参考下
尽管排列组合是生活中经常遇到的问题,可在程序设计时,不深入思考或者经验不足都让人无从下手。由于排列组合问题总是先取组合再排列,并且单纯的排列问题相对简单,所以本文仅对组合问题的实现进行详细讨论。以在n个数中选取m(0&m&=n)个数为例,问题可分解为:
1. 首先从n个数中选取编号最大的数,然后在剩下的n-1个数里面选取m-1个数,直到从n-(m-1)个数中选取1个数为止。
2. 从n个数中选取编号次小的一个数,继续执行1步,直到当前可选编号最大的数为m。
很明显,上述方法是一个递归的过程,也就是说用递归的方法可以很干净利索地求得所有组合。
下面是递归方法的实现:
/// 求从数组a[1..n]中任选m个元素的所有组合。
/// a[1..n]表示候选集,n为候选集大小,n&=m&0。
/// b[1..M]用来存储当前组合中的元素(这里存储的是元素下标),
/// 常量M表示满足条件的一个组合中元素的个数,M=m,这两个参数仅用来输出结果。
void combine( int a[], int n, int m,& int b[], const int M )
&for(int i=n; i&=m; i--)&& // 注意这里的循环范围
& b[m-1] = i - 1;
& if (m & 1)
&& combine(a,i-1,m-1,b,M);
& else&&&&&&&&&&&&&&&&&&&& // m == 1, 输出一个组合
&& for(int j=M-1; j&=0; j--)
&&& cout && a[b[j]] && " ";
&& cout &&
因为递归程序均可以通过引入栈,用回溯转化为相应的非递归程序,所以组合问题又可以用回溯的方法来解决。为了便于理解,我们可以把组合问题化归为图的路径遍历问题,在n个数中选取m个数的所有组合,相当于在一个这样的图中(下面以从1,2,3,4中任选3个数为例说明)求从[1,1]位置出发到达[m,x](m&=x&=n)位置的所有路径:
1& 2& 3& 4
&&& 2& 3& 4
&&&&&&& 3& 4
上图是截取n×n右上对角矩阵的前m行构成,如果把矩矩中的每个元素看作图中的一个节点,我们要求的所有组合就相当于从第一行的第一列元素[1,1]出发,到第三行的任意一列元素作为结束的所有路径,规定只有相邻行之间的节点,并且下一行的节点必须处于上一行节点右面才有路径相连,其他情况都无路径相通。显然,任一路径经过的数字序列就对应一个符合要求的组合。
下面是非递归的回溯方法的实现:
代码如下:/// 求从数组a[1..n]中任选m个元素的所有组合。
/// a[1..n]表示候选集,m表示一个组合的元素个数。
/// 返回所有组合的总数。
int combine(int a[], int n, int m)
&m = m & n ? n :
&int* order = new int[m+1];&&&
&for(int i=0; i&=m; i++)
& order[i] = i-1;&&&&&&&&&&& // 注意这里order[0]=-1用来作为循环判断标识
&int count = 0;&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&bool flag =&&&&&&&&&& // 标志找到一个有效组合
&while(order[0] == -1)
& if(flag)&&&&&&&&&&&&&&&&&& // 输出符合要求的组合
&& for(i=1; i&=m; i++)&&&&&&&&&&&&&&&&&&&
&&& cout && a[order[i]] && " ";
&& cout &&
&& count++;
& order[k]++;&&&&&&&&&&&&&&& // 在当前位置选择新的数字
& if(order[k] == n)&&&&&&&&& // 当前位置已无数字可选,回溯
&& order[k--] = 0;
& if(k & m)&&&&&&&&&&&&&&&&& // 更新当前位置的下一位置的数字&&&&&&&&&
&& order[++k] = order[k-1];
& if(k == m)
下面是测试以上函数的程序:
int main()
&const int N = 4;
&const int M = 3;
&int a[N];
&for(int i=0;i&N;i++)
& a[i] = i+1;
&// 回溯方法
&cout && combine(a,N,3) &&
&// 递归方法
&int b[M];
&combine(a,N,M,b,M);
&return 0;
由上述分析可知,解决组合问题的通用算法不外乎递归和回溯两种。在针对具体问题的时候,因为递归程序在递归层数上的限制,对于大型组合问题而言,递归不是一个好的选择,这种情况下只能采取回溯的方法来解决。
n个数的全排列问题相对简单,可以通过交换位置按序枚举来实现。STL提供了求某个序列下一个排列的算法next_permutation,其算法原理如下:
1. 从当前序列最尾端开始往前寻找两个相邻元素,令前面一个元素为*i,后一个元素为*ii,且满足*i&*ii;
2. 再次从当前序列末端开始向前扫描,找出第一个大于*i的元素,令为*j(j可能等于ii),将i,j元素对调;
3. 将ii之后(含ii)的所有元素颠倒次序,这样所得的排列即为当前序列的下一个排列。
其实现代码如下:
template &class BidirectionalIterator&
bool next_permutation(BidirectionalIterator first, BidirectionalIterator last)
& if (first == last)&& // 空
& BidirectionalIterator i =
& if (i == last)&&&&&& // 只有一元素
& i =&&&&&&&&&&&&&&&&&&&&&&&&& // i 指向尾端
& BidirectionalIterator ii =
& // 以上,i定一M()相
& if (*i & *ii)&&&&&&&&&&&&&&&&&&&& // 如果前一元素小於後一元素
&& BidirectionalIterator j =& // 令 j指向尾端
&& while (!(*i & *--j));&&&&&&&&&&& // 由尾端往前找,直到遇上比 *i 大的元素
&& iter_swap(i, j);&&&&&&&&&&&&&&&& // 交Q i, j
&& reverse(ii, last);&&&&&&&&&&&&&& //
ii 之後的元素全部逆向重排
& if (i == first)&&&&&&&&&&&&&&&&&& // M行至最前面了
&& reverse(first, last);&&&&&&&&&&& // 全部逆向重排
下面程序演示了利用next_permutation来求取某个序列全排列的方法:
int main()
&int ia[] = {1,2,3,4};
&vector&int& iv(ia,ia+sizeof(ia)/sizeof(int));
&copy(iv.begin(),iv.end(),ostream_iterator&int&(cout," "));
&while(next_permutation(iv.begin(),iv.end()))
& copy(iv.begin(),iv.end(),ostream_iterator&int&(cout," "));
&return 0;
注意:上面程序中初始序列是按数值的从小到大的顺序排列的,如果初始序列无序的话,上面程序只能求出从当前序列开始的后续部分排列,也就是说next_permutation求出的排列是按排列从小到大的顺序进行的。
您可能感兴趣的文章:
上一篇:下一篇:
最 近 更 新
热 点 排 行
12345678910定义两个函数
分别输出m个数中n个数的排列 与组合,该怎么处理_C语言大全_优良自学吧 |
当前位置: >
> 定义两个函数
分别输出m个数中n个数的排列 与组合,该怎么处理优良自学吧提供定义两个函数
分别输出m个数中n个数的排列 与组合,该怎么处理,定义两个函数 分别输出m个数中n个数的排列 与组合例如 1 2 3 这三个数 两个数的排列与组合排列: 1 2; 1 3;2 1; 2 3;3 1;3 3;组合:1 2; 1 3; 2 3; &跪求编程原理 注意 是原理啊定义两个函数
分别输出m个数中n个数的排列 与组合例如 1 2 3 这三个数 两个数的排列与组合排列:
1 2; 1 3;2 1; 2 3;3 1;3 3;组合:1 2; 1 3;
2 3; &跪求编程原理 注意 是原理啊
即使没有代码 也行!!!
我要的是方法!!1------解决方案--------------------C/C++ code
#include &stdio.h&
#include &stdlib.h&
bool find_arr( int a[], int length , int value )
for( int i = 0; i & ++i )
if( a[i] == value )
int main()
int i = 0, j = 0;
printf(&input the array numbers: &);
scanf(&%d&,&len);
arr = new int[len];
for( i = 0; i & ++i )
printf(&input the %d number: &,i + 1);
scanf(&%d&,&arr[i]);
printf(&排列:&);
for( i = 0; i & ++i )
for( j = 0; j & ++j )
if( arr[i] != arr[j] )
printf(&%d
%&,arr[i],arr[j]);
printf(&\n组合:&);
for( i = 0; i & ++i )
for( j = i + 1; j & ++j )
printf(&%d
%&,arr[i],arr[j]);
printf(&\n&);
------解决方案--------------------探讨C/C++ code#include &stdio.h&#include &stdlib.h&bool find_arr( int a[], int length , int value ){
for( int i = 0; i & ++i )
if( a[i] == value )
return true……
------解决方案--------------------
C/C++ code
求(1...m)中,n个数的组合
本程序的思路是开一个数组,其下标表示1到m个数,数组元素的值为1表示其下标代表的数被选中,为0则没选中。
首先初始化,将数组前n个元素置1,表示第一个组合为前n个数。
然后从左到右扫描数组元素值的“10”组合,找到第一个“10”组合后将其变为“01”组合,
同时将其左边的所有“1”全部移动到数组的最左端。
当第一个“1”移动到数组的m-n的位置,即n个“1”全部移动到最右端时,就得到了最后一个组合。
例如求5中选3的组合:
#include &stdio.h&
#include &malloc.h&
void output(int *num, int m)
for(i = 0; i & ++i)
if(*(num+i) == 1)
printf(&%d
printf(&\n&);
//检测n个“1”是否全部移动到最右端
//是则返回1
int check(int *num, int m, int n)
int i, flag = 1;
for(i = m-1; i & m-n-1; --i)
if(*(num+i) == 0)
void chooseNum(int m, int n)
int *num, i, j,
num = (int*)malloc(sizeof(int)*m);
for(i = 0; i & ++i)//前n个元素置1
*(num+i) = 1;
if(m == n)
output(num, m);
for(i = i & ++i)//后面m-n个元素置0
*(num+i) = 0;
output(num, m);
count = 0;
//找到第一个“10”组合后将其变为“01”组合
for(i = 0; i & m-1; ++i)
if(*(num+i) == 1 && *(num+i+1) == 0)
*(num+i) = 0;
*(num+i+1) = 1;
if(*(num+i) == 1)
//将其左边的所有“1”全部移动到数组的最左端
for(j = 0; j & ++j)
if(j & count)
*(num+j) = 1;
*(num+j) = 0;
output(num, m);
if(check(num, m, n) == 1)
free(num);
int main()
int m = 3, n = 2;
//scanf(&%d%d&, &m, &n);
chooseNum(m, n);
------解决方案--------------------C/C++ code
#include &stdio.h&
#include &stdlib.h&
#define MAX_NUM 26
int comb[MAX_NUM];
int c1,c2;
void combination(int m, int n)
for (i = i &= i--){
/* 选择当前的“头”元素 */
if (n & 1){
/* 进入下一次更小的组合问题 */
combination(i - 1, n - 1);
/* 满了需要的组合数,输出 */
for (j = comb[0]; j & 0; j--){
printf(&%c&, 65+c1-comb[j]);
printf(&\n&);
int main(int argc, char *argv[])
if (argc&3) {
printf(&%s 组合下标 组合上标\n&,argv[0]);
c1=atoi(argv[1]);
if (c1&1||26&c1) {
printf(&1&=组合下标&=26\n&);
c2=atoi(argv[2]);
if (c2&1||c1&c2) {
printf(&1&=组合上标&=组合下标\n&);
comb[0]=c2;
combination(c1, c2);
/* C(4, 2) */
}(本文来自互联网,不代表搜站(/)的观点和立场)本站所有内容来自互联网,若本站收录的信息无意侵犯了贵司版权,请给我们来信(),我们会及时处理和回复,谢谢编辑推荐最近更新组合数 c语言_百度知道
组合数 c语言
& unsigned long int a[40];n+1; & && & }&); {printf(&& & if(i==n) & & return(m);& &i++)& &nbsp.h&gt. & &/zhidao/wh%3D600%2C800/sign=6bea9ca7a8fce1f88bbe/30adcbefaf34aa1cc7cd98c109d49;n+1; & & &&i&lt,n); & &nbsp://g; & for(i=1://g.hiphotos,&n);}& printf(&0) &unsigned long int temp(int x); & & & && return 0; if(n& &/zhidao/wh%3D450%2C600/sign=033f0c5fa586cdfc0d5cf9/30adcbefaf34aa1cc7cd98c109d49; & while(scanf(&&/zhidao/pic/item/30adcbefaf34aa1cc7cd98c109d49; &nbsp.hiphotos://g; & &i++)&nbsp.jpg" />#include& &; & && &nbsp,a[i]).jpg" esrc=" &%d&m=m*i; &nbsp.i++)&int main(){& && for(i=0; & &a[i]=(temp(n))/(temp(n-i)*temp(i)); for(i=0;%ld& &2^%d=&quot,i; &nbsp. printf(&; & &x+1; &&i&lt.h& else& {&&#include&+& & &nbsp.jpg" target="_blank" title="点击查看大图" class="ikqb_img_alink"><img class="ikqb_img" src=" & &}unsigned long int temp(int x){ &i& &; &unsigned long int m=1; &}为什么14后答案就不对了;&nbsp!=EOF)&& &nbsp<a href="http
提问者采纳
要简化一下其实这是杨辉三角形。边上可以认为是0(2) = &nbsp,不能直接按公式算,下一行等上行同一位置上左右两个数相加; &nbsp!很大n;1 2 1(3) = &nbsp,只要保上一行
那利用杨辉三角形该怎么写呢
int&main()&{ int&i,&j,&n&=&5; int&a[34]&=&{0};&//33+1,必须全部初始化为0. for&(j&=&0;&j&&&n;&++j)&{
a[0]&=&1;&
for&(i&=&j&+&1;&i&&&0;&--i)
a[i]&=&a[i-1]&+&a[i]; } for&(i&=&0;&i&&&n&+&1;&++i)&
printf(&%d&&,&a[i]); printf(&\n&);}
提问者评价
来自:求助得到的回答
来自团队:
其他类似问题
为您推荐:
c语言的相关知识
其他1条回答
14!太大了,超出了unsigned long int所能表示的范围,用double类型的数据吧
等待您来回答
下载知道APP
随时随地咨询
出门在外也不愁

我要回帖

更多关于 c语言猜数字游戏 的文章

 

随机推荐