排列组合生成算法C++实现之字典序法
排列组合的生成算法
![排列组合的生成算法](https://img.taocdn.com/s3/m/a2f15badd1f34693daef3e22.png)
2.组合的生成: 递归 由上一个组合生成下一个组合
program zuhe; const n=6;m=4; var a:array[0..m] of integer; i,j:integer; procedure print; var i:integer; begin for i:=1 to m do write(a[i]); writeln; end; procedure try(dep:integer); var i:integer; begin for i:=a[dep-1]+1 to n-(m-dep) do begin a[dep]:=i; if dep=m then print else try(dep+1); end end; begin a[0]:=0; try(1); end.
字典序法 按照字典序求下一个排列的算法 例字符集{1,2,3},较小的数字较先,这样按字典序生成的 全排列是:123,132,213,231,312,321。 生成给定全排列的下一个排列 所谓一个全排ห้องสมุดไป่ตู้的下一个排列就是这一个排列与下一个排列之间没有其他的排列。 这就要求这一个排列与下一个排列有尽可能长的共同前缀,也即变化限制在尽可能短的后 缀上。 (1)求满足关系式pj-1<pj的j的最大值,设为i,即 i=max{j| pj-1<pj} (2)求满足关系式pi-1<pk的k的最大值,设为j,即 j=max{k| pi-1<pk} (3)将pi-1与pj互换 (4)将互换后的排列,从i开始到n之间的数逆转。
下一个组合的概念 给定集合S={1,2,…,n},如何找出S的所有k—组合? 因为组合无顺序,所以对S的任何一个k—组合{a1a2…ak},我们恒假定a1<a2<…<ak. 在这个假定下恒有ai≤n-k+i,并称n-k+i为ai的最大值. 设{a1a2…ak} 和{b1b2…bk}是S的两个不同的k—组合.如果(a1a2…ak)(b1b2…bk), 并且不存在异于{a1a2…ak}和{b1b2…bk}的k—组合{c1c2…ck},使得 (a1a2…ak) (c1c2…ck) (b1b2…bk) 则称{b1b2…bk}为{a1a2…ak} 的下一个组合. 组合生成算法: 步骤1 置{a1a2…ak}={1,2,…,k}; 步骤2 设已有一个k—组合{a1a2…ak}. 置i:=k: ① 若ai<n-k+i,则令 bi=ai+1 bj+1=bj+1,j=i, i+1, …,k-1 并置 {a1a2…ak}:={a1a2…ai-1bibi+1…bk} 返回步骤2; ② 若ai=n-k+i: 如果i>1,置i:=I-1,返回①; 如果i=1,终止. 这样,所有k—组合即可数遍.
序数法 字典法 邻位互换法 求解全排列 c语言 编程
![序数法 字典法 邻位互换法 求解全排列 c语言 编程](https://img.taocdn.com/s3/m/8bed2f2531126edb6f1a10f9.png)
பைடு நூலகம்void disp()
{/*打印值*/
int i;
static int count=0;
for (i=0;i<N;i++)
{
printf("%d",V(i));
{/*返回数组中大于a[f]的最后一个数下标*/
while(--length)
{
if (a[length]>a[f])
{
return length;
}
}
return -1;
}
int * swap_dx(int src,int dec,int a[],int length)
/*出下一个排序直至最后一个排列4321,然后在逆序,依次计算出2413的上一个排*/
/*序直至1234 */
/************************************************************************/
#define N 5 /*求解N阶全排列*/
/* 邻位互换法,求解全排列 */
/* */
/* 在此方法中,我们规定活动数为其箭头所指的邻位数小于该数,你也可以自 */
/*己定义一个方向和规则,但数的初始排列和方向必须对应起来。 */
/************************************************************************/
字典排序法
![字典排序法](https://img.taocdn.com/s3/m/63dc4f40571252d380eb6294dd88d0d233d43c31.png)
字典排序法
《字典排序法》是一种经常用在计算机编程中的排序算法,它是指给定一个列表或者数组,按照字典顺序,由最低到最高的方式对所有元素进行排序。
这种方法可以比较容易地实现,并且排序效率也比较高,有许多应用场景。
字典排序法是根据元素的值来进行排序,通常情况下,排序会按照字母表顺序,由最低到最高,从而获得排序结果。
它可以被用在多种编程语言中,比如 c++ 、 c# 、 java 、 python 中的列表/数组排序等。
字典排序法的实现很简单,看下面的实现,这是一个python实现的示例:
def sort_dict(x):
x.sort(key=lambda x:x[0])
return x
上面提供的示例函数接受一个由多个元组组成的列表,用key参数传递lambda函数,以输入列表中的每个元组中的第一个元素作为排序标准,这是一个非常常见的字典排序的实现。
字典排序法的应用非常广泛,常见的应用场景如下:
1)字典排序法可以用于对元素的排序,比如对字符串的排序,或者对计算机系统中的文件名称的排序;
2)字典排序法也可以用于多个字典的排序,比如对数据库中的表格字段值的排序,或者对JSON对象中字段值的排序;
3)字典排序法还可以用于对有序列表进行排序,比如进行排序后可以借助有序列表快速搜索对应的值;
4)字典排序法也可以用于对树结构中的节点进行排序,使得后续进行搜索操作更加轻松高效;
5)字典排序法还可以用于实现元素的组合排序,因为字典排序法可以在元素的排序上实现可控的灵活性。
以上就是《字典排序法》的具体介绍,它的实现非常简单,并且具有广泛的应用,因此可以用于解决各种问题,是一种非常有用的算法之一。
组合数学:1-2 排列组合的生成
![组合数学:1-2 排列组合的生成](https://img.taocdn.com/s3/m/49d1a4feaef8941ea76e05db.png)
对上述过程,一般地,对于i,将前一步所得的每 一排列重复 i 次,然后将 i 由第一排的最后往前移, 至最前列,正好走了 i 次,下一个接着将 i 放在下一 排列的最前面,然后依次往后移,一直下去即得 i 元排列。 下面我们用较正式的语言来说这件事。
对给定的一个整数k,我们赋其一个方向,即在其 上写一个箭头(指向左侧或右侧)
1.2 排列组合生成算法
1. 全排列的生成算法 2. 组合的生成算法
3. 一般排列的生成算法
1. 全排列的生成算法
全排列的生成算法就是对于给定的字符集,用有 效的方法将所有可能的全排列无重复无遗漏地枚 举出来。
这里介绍4种全排列算法: (A) 直接生成法 (B) 序数法 (C) 字典序法 (D) 换位法
n的p进制表示: n a i p i , 0 a i p
i 1
i 1 k
我们来看另一种表示
n!=((n-1)+1)(n-1)!=(n-1)(n-1)!+(n-1)!, (n-1)!=(n-2)(n-2)!+(n-2)!, …, 故 n!= (n-1)(n-1)!+ (n-2)(n-2)!+…+2×2!+2!
3. 一般排列的生成算法
n中取r的排列生成可以由组合生成和全排列生成 结合而得到。
839647521的下一个为839651247。
一般而言,设P是[1,n]的一个全排列。
P=P1P2…Pn=P1P2…Pj-1PjPj+1…Pk-1PkPk+1…Pn
(1) 找出 j=max{ i |Pi<Pi+1},k=max{ i |Pi>Pj}; (2) 对换 Pj,Pk; (3) 将 Pj+1…Pk-1PjPk+1…Pn翻转, P1P2…Pj-1PkPn…Pk+1PjPk-1…Pj+1即是P的下一个。 该算法的优点是排列清晰,而且保持着字典序。 缺点是算法较繁琐。
排列组合生成算法之字典序法和换位法动画ppt
![排列组合生成算法之字典序法和换位法动画ppt](https://img.taocdn.com/s3/m/48f56b08c5da50e2524d7fbc.png)
2
例题:请写出1234的全排列
Step1:以1234开始排序,在每个数字上标一向 左箭头。 箭头所指一侧相邻的数若比它小,则称该数处于活 动状态 Step2:找最大的处于活动状态的数m Step3:将m与其箭头所指的邻数互换位置 Step4:将所得排列中比m大的数p的方向调整, 即改为相反方向 Step5:重复Step2~Step4直至无活动状态的数
2
例题:请写出1234的全排列 1 2 3 4
1234
2
例题:请写出1234的全排列 1 2 4 3
1234 1243
2
例题:请写出1234的全排列 1 4 2 3
1234 1243 1423
2
例题:请写出1234的全排列 4 1 2 3
1234 1243 1423 4123
2
例题:请写出1234的全排列 4 1 3 2
i-1者)
(4) 反排pj后面的数得到(q):
p1…pi-2 pj pnpj+1pi-1pj-1 ….pi+1 pi
1
例题:设有排列(p) =2763541, 按照字典式排 序, 它的下一个排列是谁?
Step1:求 i=maxj pj-1pj (找最后一个正序)
2
7
6
3
5
4
1
1
例题:设有排列(p) =2763541, 按照字典式排序, 它的下一个 排列是谁?
2
例题:请写出1234的全排列
Step1:以1234开始排序,在每个数字上标一向 左箭头。 箭头所指一侧相邻的数若比它小,则称该数处于活 动状态 Step2:找最大的处于活动状态的数m Step3:将m与其箭头所指的邻数互换位置 Step4:将所得排列中比m大的数p的方向调整, 即改为相反方向 Step5:重复Step2~Step4直至无活动状态的数
排列组合的一些算法
![排列组合的一些算法](https://img.taocdn.com/s3/m/e197b6e4541810a6f524ccbff121dd36a32dc4f9.png)
排列组合的⼀些算法排列组合有多种实现⽅法,下⾯介绍整理的⼀些⽅法。
⼀、最简单直接的就是递归原理⽐较直接:计算⼀个集合的组合,⾸先选择⼀个元算,然后在剩下的集合中选择剩下的元素。
看下⾯的源代码:/*************************** 计算⼀个集合的组合*************************/#include<stdlib.h>#include<assert.h>/************************** 递归: ⾸先选择⼀个元素,然后在剩下的集合中选择其余元素************************/typedef struct LiStack{char element;struct LiStack* prev;struct LiStack* next;}LiStack;typedef struct SqStack{char *elements;int top; /*栈指针*/}SqStack;//采⽤链式存储的栈, 双向链表:由栈顶指向栈底void CalCombinationLi(const char Elements[], int SetLg, int k, LiStack *StackHead, LiStack *StackTail){//Elements:集合, SetLg:集合长度, k:要选取的元素个数, stackHead:指向栈顶, StackTail:指向栈底LiStack* StackTmp;LiStack* StackN;int i;assert(k<=SetLg);//如果要选取的元素个数超过集合长度,则出错if(k==0){//输出该次选取的元素组合StackTmp = StackTail;while(StackTmp){printf("%c ",StackTmp->element);StackTmp = StackTmp->prev;}printf(""n");return;}//从该集合中顺序选取⼀个元素[i], 因为共选取k个元素, 所以最后⼀个可选择的元素为[SetLg-k]//然后从剩下的集合[i+1:end]中选取其余的k-1个元素//这样就构成了从集合(长度为SetLg)中选取k个元素, 按字典序的组合for(i=0; i<=SetLg-k; ++i){//将元素[i]压栈StackN = (LiStack*)malloc(sizeof(LiStack));StackN->element = Elements[i];StackN->next = NULL;StackN->prev = NULL;if(StackHead){StackHead->prev = StackN;StackN->next = StackHead;}else{StackTail = StackN;}StackHead = StackN;CalCombinationLi(Elements+i+1, SetLg-i-1, k-1, StackHead, StackTail);//从剩下的集合中选取k-1个元素//将元素[i]弹出栈StackTmp = StackHead;StackHead = StackHead->next;free(StackTmp);if(StackHead){StackHead->prev = NULL;}else{StackHead = NULL;StackTail = NULL;}}}//采⽤顺序存储的栈void CalCombinationSq(const char Elements[], int SetLg, int k, SqStack *stack){//Elements:集合, SetLg:集合长度, k:要选取的元素个数, stack:栈assert(k<=SetLg);int i;if(k==0){//输出此次选取的元素组合for(i=0; i<=stack->top; i++)//从栈底到栈顶{printf("%c ",stack->elements[i]);}printf(""n");return;}for(i=0; i<=SetLg-k; i++){//将元素[i]压栈stack->top++;stack->elements[stack->top]=Elements[i];CalCombinationSq(Elements+i+1, SetLg-i-1, k-1, stack);//将元素[i]弹出栈stack->top--;}}//测试int main(){char elements[] = {'a', 'b', 'c', 'd'};const int NUM = sizeof(elements) / sizeof(elements[0]);LiStack *StackHead=NULL, *StackTail=NULL;int i;SqStack *stack=(SqStack *)malloc(sizeof(SqStack));stack->elements = (char *)malloc(sizeof(elements));for(i=1; i<=NUM; i++){//CalCombinationLi(elements, NUM, i, StackHead, StackTail);CalCombinationSq(elements, NUM, i, stack);}}排列的源程序和上⾯的类似,其实上⾯的组合输出具有顺序性,和排列的输出没有多⼤的区别。
排列组合生成算法
![排列组合生成算法](https://img.taocdn.com/s3/m/a4d20ad1ce2f0066f53322dc.png)
《组合数学》第二讲排列组合生成算法1一. 排列生成算法z排列生成有几种典型算法, 这些算法都很有成效. 它们在实际中具有广泛应用价值.1.序数法2.字典序法3.邻位互换法(Johnson-Trotter)4.轮转法31. 序数法z序数法基于一一对应概念.z先在排列和一种特殊的序列之间建立一种一一对应关系, 然后再给出由序列产生排列的方法z因为序列的产生非常方便, 这样我们就可以得到一种利用序列来生成排列的方法.z如何建立这种一一对应?45z 思路类似数的10进制、2进制和p 进制表示.;90,1010≤≤=∑−=k m k k k a a n;10,210≤≤=∑−=k m k k k a a n.10,1−≤≤=∑−=p a p a n k m k kkz这相当于自然数与某种序列之间建立了一一对应关系.z可以利用置换来表示整数:n!=n(n-1)! =(n-1+1)(n-1)!= (n-1)(n-1)!+(n-1)!(n-1)!= (n-2)(n-2)!+(n-2)!n!= (n-1)(n-1)!+ (n-2)(n-2)!+ (n-3)(n-3)!+…+2•2!+1•1!+16z n!-1=(n-1) (n-1)!+(n-2) (n-2)!+(n-3) (n-3)!+ …+2•2!+1•1!z可以证明, 从0到n!-1之间的任何整数m 都可唯一地表示为:m=a n-1 (n-1)!+a n-2 (n-2)!+…+a2•2!+a1•1!其中0≤a≤i, i=1,2, …,n-1.iz m与序列(a n-1,a n-2 ,…a2,a1)一一对应z书中有确定这些系数的方法.z例如:10=1⋅3!+2⋅2!+0⋅1!7z因为满足条件0≤a≤i, 1≤i≤n-1 (2.1)i的序列(a, a n-2, …, a2, a1)n-1共有n!个, 这恰好与0到n!-1的n!个整数一一对应.z需要建立满足条件(2.1)的n!个序列(a, a n-2, …, a2, a1)和n元集合S的n-1全部排列之间的一一对应关系.89z 还需要给出一种办法, 由每个满足条件(2.1)的序列(a n -1,a n -2, …,a 2,a 1)可生成唯一的一个排列.z 这样我们就可以产生出所有的排列. z 怎么样由一个满足条件(2.1)的序列产生一个n 阶排列?z 如何把1,2,…,n 的一个排列与一个满足条件(2.1)的序列建立起直接的关系?10z 行列式定义中有逆序数的概念, 就是一个排列中违反自然顺序的数对: 比如12354的逆序数为1, 而43215的逆序数为6.z 设p 1p 2…p n 是任意一个n 元排列, 则i +1后面比i +1小的数字的个数a i 总不超过i , 即a i ≤i , i =1,2,…,n -1.z 这样自然由一个排列得到一个序列(a n -1,a n -2,…,a 2,a 1), 而且满足条件(2.1).11z 我们可以如下建立序列与排列的对应:z 设序列(a n -1,a n -2, …,a 2,a 1)满足条件(2.1).则它所对应的排列为(p)=p 1p 2…p n , 其中a i 可以看作是排列(p)中数i +1所在位置后面比i +1小的数的个数.z 要说明这种对应的合理性, 必须清楚. 如何由序列产生出它所对应的排列.z 我们通过一个具体的例题说明思想方法.12例2.1(1) 4213→(301)4后面比4小的数的个数a 3=3; 3后面比3小的数的个数a 2=0; 2后面比2小的数的个数a 1=1.(2) (301) →4213由a 3=3知1,2,3都在4的后面; 由a 2=0知1,2都在3前面; 由a 1=1知1在2后面.(3) (4213)↔(a 3a 2a 1)=(301).2. 字典序法对给定的字符集中的字符规定了一个先后关系,在此基础上规定两个全排列的先后是从左到右逐个比较对应的字符的先后。
排列组合生成算法
![排列组合生成算法](https://img.taocdn.com/s3/m/b45f2e6648d7c1c708a14539.png)
c几几的计算方法排列组合
![c几几的计算方法排列组合](https://img.taocdn.com/s3/m/f204eec5b8d528ea81c758f5f61fb7360b4c2bc1.png)
c几几的计算方法排列组合C语言中的排列组合问题是一类常见的数学问题,在编程中经常会遇到。
本文将为您介绍C语言中排列组合的基本概念、计算方法和应用场景。
一、什么是排列组合排列是指从n个不同元素中,按照一定的顺序取出r个元素,共有多少种不同的取法。
其中,n称为排列的总数,r称为每个排列中的元素个数。
组合是指从n个不同元素中,选取出r个元素,不考虑元素的顺序,共有多少种不同的取法。
其中,n称为组合的总数,r称为每个组合中的元素个数。
二、C语言中的排列函数C语言中可以使用递归的方式进行排列的计算。
以下是一个计算排列的C语言函数:```c#include <stdio.h>int fact(int n) {if (n <= 1) {return 1;} else {return n * fact(n - 1);}}int permutation(int n, int r) {return fact(n) / fact(n - r);}int main() {int n, r;printf("请输入排列的总数n和每个排列中的元素个数r:");scanf("%d %d", &n, &r);if (r > n) {printf("输入错误!r不能大于n。
\n");return 0;}int result = permutation(n, r);printf("结果为:%d\n", result);return 0;}```在上述代码中,`fact`函数用于计算阶乘,`permutation`函数用于计算排列。
程序首先从用户输入中获取排列的总数n和每个排列中的元素个数r,然后调用`permutation`函数计算结果并输出。
三、C语言中的组合函数C语言中也可以使用递归的方式进行组合的计算。
以下是一个计算组合的C语言函数:```c#include <stdio.h>int fact(int n) {if (n <= 1) {return 1;} else {return n * fact(n - 1);}}int combination(int n, int r) {return fact(n) / (fact(r) * fact(n - r));}int main() {int n, r;printf("请输入组合的总数n和每个组合中的元素个数r:"); scanf("%d %d", &n, &r);if (r > n) {printf("输入错误!r不能大于n。
全排列C编程
![全排列C编程](https://img.taocdn.com/s3/m/eb48e36901f69e3143329462.png)
全排列C++编程全排列的生成算法全排列的生成算法就是对于给定的字符集,用有效的方法将所有可能的全排列无重复无遗漏地枚举出来。
任何n个字符集的排列都可以与1~n的n个数字的排列一一对应,因此在此就以n个数字的排列为例说明排列的生成法。
n个字符的全体排列之间存在一个确定的线性顺序关系。
所有的排列中除最后一个排列外,都有一个后继;除第一个排列外,都有一个前驱。
每个排列的后继都可以从它的前驱经过最少的变化而得到,全排列的生成算法就是从第一个排列开始逐个生成所有的排列的方法。
全排列的生成法通常有以下几种:字典序法递增进位数制法递减进位数制法邻位交换法递归类算法1.字典序法字典序法中,对于数字1、2、3......n的排列,不同排列的先后关系是从左到右逐个比较对应的数字的先后来决定的。
例如对于5个数字的排列12354和12345,排列12345在前,排列12354在后。
按照这样的规定,5个数字的所有的排列中最前面的是12345,最后面的是54321。
字典序算法如下:设P是1~n的一个全排列:p=p1p2......pn=p1p2......pj-1pjpj+1......pk-1pkpk+1......pn 1)从排列的右端开始,找出第一个比右边数字小的数字的序号j(j从左端开始计算),即j=max{i|pi<pi+1}2)在pj的右边的数字中,找出所有比pj大的数中最小的数字pk,即k=max{i|pi>pj}(右边的数从右至左是递增的,因此k是所有大于pj的数字中序号最大者)3)对换pi,pk4)再将pj+1......pk-1pkpk+1pn倒转得到排列p''=p1p2.....pj-1pjpn.....pk+1pkpk-1.....pj+1,这就是排列p的下一个下一个排列。
例如839647521是数字1~9的一个排列。
从它生成下一个排列的步骤如下:自右至左找出排列中第一个比右边数字小的数字4 839647521在该数字后的数字中找出比4大的数中最小的一个5 839647521将5与4交换839657421将7421倒转839651247所以839647521的下一个排列是839651247。
数字排列组合——快速计算全排列的方法
![数字排列组合——快速计算全排列的方法](https://img.taocdn.com/s3/m/21685c09effdc8d376eeaeaad1f34693daef10d8.png)
数字排列组合——快速计算全排列的方法数字排列组合是数学中一个重要的概念,它涉及到对一组数字进行不同顺序的排列。
在实际生活中,我们经常遇到需要计算全排列的情况,比如在密码破解、游戏策略等方面。
本文将介绍一种快速计算全排列的方法,帮助读者更高效地处理这类问题。
首先,我们来看一个简单的例子。
假设有三个数字:1、2、3。
我们需要计算这三个数字的全排列。
传统的方法是使用递归,但这种方法在处理大量数字时效率较低。
现在,我们介绍一种更快速的方法——字典序法。
字典序法的基本思想是从最小的排列开始,逐步生成下一个更大的排列,直到达到最大排列为止。
具体步骤如下:1. 将给定的数字按照从小到大的顺序排列,得到初始排列。
2. 从右往左找到第一个比右边数字小的数字,记为a。
3. 从右往左找到第一个比a大的数字,记为b。
4. 交换a和b。
5. 将a右边的数字按照从小到大的顺序排列。
6. 重复步骤2-5,直到无法找到满足条件的a和b。
通过上述步骤,我们可以依次生成所有的全排列。
下面我们用这种方法来计算数字1、2、3的全排列。
初始排列为1、2、3。
从右往左找到第一个比右边数字小的数字,即2。
再从右往左找到第一个比2大的数字,即3。
交换2和3,得到排列1、3、2。
接下来,将3右边的数字按照从小到大的顺序排列,得到排列1、3、2。
此时,无法找到满足条件的a和b,所以排列1、3、2已经是最大排列。
我们继续上述步骤,从右往左找到第一个比右边数字小的数字,即1。
再从右往左找到第一个比1大的数字,即2。
交换1和2,得到排列2、3、1。
将3右边的数字按照从小到大的顺序排列,得到排列2、1、3。
此时,无法找到满足条件的a和b,所以排列2、1、3已经是最大排列。
最后,我们得到了数字1、2、3的全排列:1、3、2和2、1、3。
通过字典序法,我们可以快速计算出任意一组数字的全排列。
这种方法的时间复杂度为O(n!),相比传统的递归方法,效率更高。
除了计算全排列,字典序法还可以用于其他相关问题,比如计算下一个排列、计算排列的逆序数等。
C语言实现的排列组合问题的通用算法、解决方法
![C语言实现的排列组合问题的通用算法、解决方法](https://img.taocdn.com/s3/m/3e0078b06aec0975f46527d3240c844769eaa039.png)
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 << endl;}}}因为递归程序均可以通过引入栈,用回溯转化为相应的非递归程序,所以组合问题又可以用回溯的方法来解决。
C++实现之字典序法
![C++实现之字典序法](https://img.taocdn.com/s3/m/78c37a0c6d175f0e7cd184254b35eefdc8d3153d.png)
C++实现之字典序法#include#includeusing namespace std;/**字典序法*1:求i=max{j| pj-1<="">*2:j=max{k| pi-1<pk}(找最后大于pi-1者)< bdsfid="72" p=""></pk}(找最后大于pi-1者)<>*3:互换pi-1与pj*4:反排pj后面的数得到(q)*5:重复步骤1*/int total = 0;//找最后一个正序int FindTheLastActiveSeq(int array[],int length) {for(int i = length - 1; i >= 1;i--){if(array[i] > array[i-1])return i-1;}return -1;}//最后大于array[index]者int FindTheLastBigger(int array[],int length,int index) {for(int i = length - 1;i > index; i--){if(array[i] > array[index])return i;}return -1;}//换pi-1与pjvoid swap(int& num1 ,int &num2){int temp = num1;num1 = num2;num2 = temp;}//反排pj后面的数得到(q)void Reverse(int array[],int length,int index) {vector vec;int vecindex = 0;for(int i = length - 1; i > index ; i--){vec.push_back(array[i]);}for(int j = index+1; j <= length -1;j++) {array[j] = vec[vecindex++];}}//打印排列void PrintArray(int array[],int length){cout <<"number: " << ++total << endl; for(int i = 0 ; i < length ; i++)cout << array[i] << " ";cout << endl;}/*生成array中数列的所有排列,array必须为递增序列,*考虑到通常array为非递增序列,我们对其进行了快速排序,*以保证程序的健壮性*/void swapA(int A[],int i, int j);int partition(int A[],int p,int r);void quicksort(int A[],int p,int r);bool Permutation(int array[],int length){int index1 = FindTheLastActiveSeq(array,length);if(index1 == -1)return false;int index2 = FindTheLastBigger(array,length,index1);if(index2 == -1)return false;swap(array[index1],array[index2]);Reverse(array,length,index1);PrintArray(array,length);return true;}int main(){int array[] = { 4,3,5,1,2};int length = sizeof(array)/sizeof(int);quicksort(array,0,length);PrintArray(array,length);while(Permutation(array,length));system("pause");return 0;}void swapA(int A[],int i, int j){int temp = A[i];A[i] = A[j];A[j] = temp;}int partition(int A[],int p,int r){int x = A[r-1];int i = p - 1;for(int j = p ; j < r-1; j++)if(A[j]<=x){i++;swapA(A,i,j);}swapA(A,i+1,r-1);return i+1;}void quicksort(int A[],int p,int r) {if(p<r)< bdsfid="176" p=""></r)<> {int q = partition(A,p,r);quicksort(A,p,q-1);quicksort(A,q+1,r);}}。
c语言中一种典型的排列组合算法
![c语言中一种典型的排列组合算法](https://img.taocdn.com/s3/m/84902613c381e53a580216fc700abb68a982ad81.png)
c语⾔中⼀种典型的排列组合算法c语⾔中的全排列算法和组合数算法在实际问题中应⽤⾮常之⼴,但算法有许许多多,⽽我个⼈认为⽅法不必记太多,最好只记熟⼀种即可,⼀招鲜亦可吃遍天全排列:#include<stdio.h>void swap(int *p1,int *p2){int t=*p1;*p1=*p2;*p2=t;}void permutation(int a[],int index,int size){if(index==size){for(int i=0;i<size;i++)printf("%d ",a[i]);printf("\n");}else{for(int j=index;j<size;j++){swap(&a[j],&a[index]);permutation(a,index+1,size);//此处⽤到递归思想swap(&a[j],&a[index]);}}}int main(){int n;scanf("%d",&n);int a[n];for(int i=0;i<n;i++)a[i]=i+1;permutation(a,0,n);return 0;}组合:#include<stdio.h>void combine(int n,int m,int a[],int b[],const int M) {for(int j=n;j>=m;j--){b[m-1]=j-1;if(m>1)combine(j-1,m-1,a,b,M);//⽤到了递归思想else{for(int i=M-1;i>=0;i--)printf("%d ",a[b[i]]);printf("\n");}}}int main(){int n,m;scanf("%d%d",&n,&m);int a[n];int b[m];for(int i=0;i<n;i++)a[i]=i+1;const int M=m; combine(n,m,a,b,M); }。
关于字符串的组合算法问题的C语言实现攻略
![关于字符串的组合算法问题的C语言实现攻略](https://img.taocdn.com/s3/m/f465382d54270722192e453610661ed9ad5155cb.png)
关于字符串的组合算法问题的C语言实现攻略关于字符串的组合算法问题的C语言实现攻略关于字符串的组合算法问题的C语言实现攻略题目:输入一个字符串,输出该字符串中字符的全部组合。
举个例子,假如输入abc,它的组合有a、b、c、ab、ac、bc、abc。
上面我们具体争论了如何用递归的思路求字符串的排列。
同样,本题也可以用递归的思路来求字符串的组合。
假设我们想在长度为n的字符串中求m个字符的组合。
我们先从头扫描字符串的第一个字符。
针对第一个字符,我们有两种选择:第一是把这个字符放到组合中去,接下来我们需要在剩下的n-1个字符中选取m-1个字符;其次是不把这个字符放到组合中去,接下来我们需要在剩下的n-1个字符中选择m个字符。
这两种选择都很简单用递归实现。
下面是这种思路的参考代码:#include#include#includeusing namespace std;#includevoid Combination(char *string ,int number,vectorresult);void Combination(char *string){ assert(string != NULL); vectorresult; int i , length = strlen(string); for(i = 1 ; i = length ; ++i) Combination(string , i ,result);}void Combination(char *string ,int number ,vectorresult){ assert(string != NULL); if(number == 0) { static int num = 1; printf(第%d个组合t,num++); vector::iterator iter = result.begin(); for( ; iter != result.end() ; ++iter)printf(%c,*iter); printf(n); return ; } if(*string == ) return ; result.push_back(*string); Combination(string + 1 , number -1 , result); result.pop_back(); Combination(string + 1 , number , result);}int main(void){ char str[] = abc; Combination(str); return 0;}由于组合可以是1个字符的组合,2个字符的字符……始终到n个字符的组合,因此在函数void Combination(char* string),我们需要一个for循环。
C实现数字按照字典序排序
![C实现数字按照字典序排序](https://img.taocdn.com/s3/m/aec2d148814d2b160b4e767f5acfa1c7ab008253.png)
一.数组按照字典序排序,使得其中某一个或者某几个数不动,其它数排序。
程序1:对于有4个数的数组,保持其中一个数不动#include "stdio.h"#include "stdlib.h"int n=4;int AA[4]={0,0,0,0};int flag[4]={0,0,1,0};//当i=1时,第n-i个数不动int AB[4]={2,2,3,4};//寻找下一个数的函数int NextNum(){AA[0]++;for(int i=0;i<n;i++){if(AA[i]>=AB[i]){if(i>=n-1)return(1);else if(flag[i+1]==1){if(i+1>=n-1)return(1);else{AA[i+2]++;AA[i]=0;i++;}}else {AA[i+1]++;AA[i]=0;}}elsebreak;}return(0);}main(){long i;for( ; ; ){for(i=3;i>=0;i--)printf("%2d",AA[i]);printf("\n");if(NextNum()==1)break;}}程序运行结果为:程序2:对于有6个数的数组,保持其中两个数不动#include "stdio.h"#include "stdlib.h"int n=5;int AA[5]={0,0,0,0,0};int flag[5]={0,1,0,1,0};//当i=1时,第n-i个数不动int AB[5]={2,2,3,3,3};//寻找下一个数的函数int NextNum(){AA[0]++;for(int i=0;i<n;i++){if(AA[i]>=AB[i]){if(i>=n-1)return(1);else if(flag[i+1]==1){if(i+1>=n-1)return(1);else{AA[i+2]++;AA[i]=0;i++;}}else {AA[i+1]++;AA[i]=0;}}elsebreak;}return(0);}main(){long i;for( ; ; ){for(i=n-1;i>=0;i--)printf("%2d",AA[i]);printf("\n");if(NextNum()==1)break;}}其运行结果为:(复制不好用)二.实现4个数的字典序全排列程序:#include <stdio.h>#include <stdlib.h>void output(int n);//输出数组void swap(int i,int j);//交换void antsort(int k,int m);//反序int NextNum(int n);//找出所有全排列int A[4]={1,2,3,4};void output(int n){int i;for(i=0;i<n;i++)printf("%d", A[i]);printf("\n");}void swap(int i,int j){int temp;temp=A[i];A[i]=A[j];A[j]=temp;}void antsort(int k,int m){int i,j;for(i=k,j=m;j>i;i++,j--)swap(i,j); }int NextNum(int n){int i,j;for( ; ; ){output(n);for(i=n-2;i>=0;i--) {if(A[i]<A[i+1])break;if(i==0)return 1;}for(j=n-1;j>i;j--){if(A[i]<A[j])break;}swap(i,j);antsort(i+1,n-1);}}main(){int i,n=4;NextNum(n);}其运行结果为:求四个数中两个数的组合程序:#include "stdio.h"#include "stdlib.h"main(){int A[4]={1,2,3,4};int i,j;for(i=0;i<4;i++)for(j=i+1;j<4;j++){printf("%2d,%2d",A[i],A[j]);printf("\n");}}程序运行结果为:。
算法之字典排序法
![算法之字典排序法](https://img.taocdn.com/s3/m/3802307601f69e3143329408.png)
算法之字典排序法2. 字典序法字典序法就是按照字典排序的思想逐一产生所有排列.设想要得到由1,2,3,4以各种可能次序产生出4!个“单词”. 肯定先排1234, 再排1243, 下来是1324, 1342, …., 4321.分析这种过程, 看如何由一个排列得到下一个排列, 并给出严格的数学描述.例2.3 设有排列(p) =2763541, 按照字典式排序, 它的下一个排列是?(q) =2764135.(1) 2763541 [找最后一个正序35](2) 2763541 [找3后面比3大的最后一个数](3) 2764531 [交换3,4的位置](4) 2764135 [把4后面的531反序排列为135即得到最后的排列(q)]求(p)=p1⋯p i-1p i…p n的下一个排列(q):(1) 求i=max{j⎪ p j-1<p j}(找最后一个正序)(2) 求j=max{k⎪ p i-1<p k}(找最后大于p i-1者)(3) 互换p i-1与p j得p1…p i-2 p j p i p i+1⋯p j-1 p i-1 p j+1…p n(4) 反排p j后面的数得到(q):p1…p i-2 p j p n⋯p j+1p i-1p j-1 ….p i+1 p i例2.4 设S={1,2,3,4}, 用字典序法求出S的全部排列. 解1234, 1243, 1324, 1342, 1423, 1432,2134, 2143, 2314, 2341, 2413, 2431,3124, 3142, 3214, 3241, 3412, 3421,4123, 4132, 4213, 4231, 4312, 4321.字典排序法C++代码:#include<iostream.h>void repailie(int *a,int n,int dp){int *bb=new int[n-dp];int *cc=new int[n-dp];int ti=0;for(int i=dp+1;i<n;i++){bb[ti++]=a[i];}for(int j=0;j<ti;j++){a[j+dp+1]=bb[ti-j-1];}//cout<<a[dp+1]<<" ";//cout<<endl;}int main(void){int n;cout<<"请输入1至无穷大的数"<<endl;cin>>n;int *a=new int[n];int p=1;//n的阶层int q=1;//循环记录int b,c;//最后一对正序int bi,ci;//记录b和c的位置int d;//最后大于b者int di;//记录d的位置for (int o=1;o<=n;o++){p=p*o;//cout<<p<<" ";}for (int i=0;i<n;i++){a[i]=i+1;cout<<a[i]<<" ";}cout<<endl;while(q<p){for(int j=n-1;j>=0;j--){if(a[j-1]<a[j]){b=a[j-1];bi=j-1;c=a[j];ci=j;break;}}//cout<<bi<<" "<<ci<<" "<<endl;for(int k=n-1;k>=0;k--)if (a[k]>b){d=a[k];di=k;break;}}//cout<<di<<endl;for(int l=0;l<n;l++){if(l==di){a[l]=b;//cout<<a[l]<<endl;}if(l==bi){a[l]=d;//cout<<a[l]<<endl;}repailie(a,n,bi);for (int m=0;m<n;m++){cout<<a[m]<<" ";}cout<<endl;++q;}}运行结果图:。
C#实现排列组合算法完整实例
![C#实现排列组合算法完整实例](https://img.taocdn.com/s3/m/46fe8a0b974bcf84b9d528ea81c758f5f61f2997.png)
C#实现排列组合算法完整实例排列组合是常见的数学问题,本⽂就以完整实例形式讲述了C#实现排列组合算法的⽅法。
分享给⼤家供⼤家参考之⽤。
具体⽅法如下:⾸先,数学中排列组合,可表⽰为:排列P(N,R)其实排列实现了,组合也就实现了,组合C(N,R)就是P(N,R)/P(R,R) ,实现这⼀功能⽐较简单的是递归算法,但考虑到递归的性能,下⾯采⽤了2种⾮递归的⽅法,具体代码如下using System;using System.Collections.Generic;namespace Test{class Program{static void Main(string[] args){Console.WriteLine(P1(6, 3));Console.WriteLine(P2(6, 3));Console.WriteLine(C(6, 2));}/// <summary>/// 排列循环⽅法/// </summary>/// <param name="N"></param>/// <param name="R"></param>/// <returns></returns>static long P1(int N, int R){if (R > N || R <= 0 || N <= 0 ) throw new ArgumentException("params invalid!");long t = 1;int i = N;while (i!=N-R){try{checked{t *= i;}}catch{throw new OverflowException("overflow happens!");}--i;}return t;}/// <summary>/// 排列堆栈⽅法/// </summary>/// <param name="N"></param>/// <param name="R"></param>/// <returns></returns>static long P2(int N, int R){if (R > N || R <= 0 || N <= 0 ) throw new ArgumentException("arguments invalid!");Stack<int> s = new Stack<int>();long iRlt = 1;int t;s.Push(N);while ((t = s.Peek()) != N - R){try{checked{iRlt *= t;}}catch{throw new OverflowException("overflow happens!"); }s.Pop();s.Push(t - 1);}return iRlt;}/// <summary>/// 组合/// </summary>/// <param name="N"></param>/// <param name="R"></param>/// <returns></returns>static long C(int N, int R){return P1(N, R) / P1(R, R);}}}希望本⽂所述对⼤家的C#程序设计有所帮助。
C语言字母排列组合的实现
![C语言字母排列组合的实现](https://img.taocdn.com/s3/m/c2bc647e27284b73f242509d.png)
C语言字母排列组合的实现曹玉坤2011-6-21目录概述 (3)需求 (3)规律 (3)实现算法 (5)难点 (6)代码 (6)概述本文档概述字母排列组合的实现算法和分析过程,着重强调在解决问题前,对问题的思考方法;注重研究问题的思路。
从问题需求开始详述解决问题的过程。
需求我们要解决的问题是,在26个字母中取出任意多个进行排列组合并把他们的组合方式打印出来。
并要求用递归的方式实现。
规律从要求中可以看出,需要使用递归的方式来解决问题。
这是对我们很好的提示。
大家知道递归时用在f(n)和f(n-1)之间有计算关系的,也就是说通过对f(n-1)的计算处理就能够得到f(n)的结果。
最终在n 等于某个具体的数值时,我们能确切的算出f(n)的值,也就是要给我们一个基点。
通过以上分析,就明确了我们的需要做的工作:第一,我们要找到f(n)和f(n-1)之间的规律;第二我们要找出那个基点,也就是能确切给出f(n)值的点。
我们先来看看下面的字母排列:aba abcba cab bca acb bac abcdcba dcab dbca dacb dbac dabc cdba cdab ………大家从上面的例子看出来规律没有?相信大家从上面的排列中一眼就能看出各个数列直接的关系,那就是:新添字母总是按照顺序插入到原有排列的之间。
如第一列是a, 第二列就是新添字母b先添加到排列a的前面,然后再排列到a的后面,这样就形成了第二行的排列ba ab。
第三行排列如规律:c先排列到ba的前面,c 再排列到ab的前面,下来c排列到b后a前形成bca, 其次c排列到ab的中间形成acb;接着c又排到ba后面,形成bac, 然后c再排列到ab后面形成abc。
这样我们就得到了第三行的字母排列。
相信大家已经会按规律排列第四行的字母排列了。
规律已经找到,那么我们选择几个字母作为基点呢?如上图排列,我们可以轻松的罗列出来一个字母时的排列,两个字母时的排列,三个字母时的排列,四个的时候,虽然我们也能根据规律将其罗列出来,但已经比较麻烦了。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
{
cout <<"number: " << ++total << endl;
for(int i = 0 ; i < length ; i++)
cout << array[i] << " ";
return false;
int index2 = FindTheLastBigger(array,length,index1);
if(index2 == -1)
return false;
swap(array[index1],array[index2]);
Reverse(array,length,index1);
PrintArray(array,length);
return true;
}
int main()
{
int array[] = { 4,3,5,1,2};
int length = sizeof(array)/sizeof(int);
void quicksort(int A[],int p,int r);
bool Permutation(int array[],int length)
{
int index1 = FindTheLastActiveSeq(array,length);
if(index1 == -1)
*5:重复步骤1
*/
int total = 0;
//找最后一个正序
int FindTheLastActiveSeq(int array[],int length)
{
for(int i = length - 1; i >= 1;i--)
{
if(array[i] > array[i-1])
{
int temp = A[i];
A[i] = A[j];
A[j] = temp;
}
int partition(int A[],int p,int r)
{
int x = A[r-1];
int i = p - 1;
for(int j = p ; j < r-1; j++) { if(Fra bibliotek<r)
{
int q = partition(A,p,r);
quicksort(A,p,q-1);
quicksort(A,q+1,r);
}
}
�
{
vec.push_back(array[i]);
}
for(int j = index+1; j <= length -1;j++)
{
array[j] = vec[vecindex++];
}
}
//打印排列
#include<iostream>
#include<vector>
using namespace std;
/*
*字典序法
*1:求 i=max{j| pj-1<pj }(找最后一个正序)
*2:j=max{k| pi-1<pk}(找最后大于pi-1者)
*3:互换pi-1与pj
*4:反排pj后面的数得到(q)
return i-1;
}
return -1;
}
//最后大于array[index]者
int FindTheLastBigger(int array[],int length,int index)
{
for(int i = length - 1;i > index; i--)
quicksort(array,0,length);
PrintArray(array,length);
while(Permutation(array,length));
system("pause");
return 0;
}
void swapA(int A[],int i, int j)
num1 = num2;
num2 = temp;
}
//反排pj后面的数得到(q)
void Reverse(int array[],int length,int index)
{
vector<int> vec;
int vecindex = 0;
for(int i = length - 1; i > index ; i--)
if(A[j]<=x){
i++;
swapA(A,i,j);
}
swapA(A,i+1,r-1);
return i+1;
}
void quicksort(int A[],int p,int r)
cout << endl;
}
/*生成array中数列的所有排列 ,array必须为递增序列,
*考虑到通常array为非递增序列,我们对其进行了快速排序,
*以保证程序的健壮性
*/
void swapA(int A[],int i, int j);
int partition(int A[],int p,int r);
{
if(array[i] > array[index])
return i;
}
return -1;
}
//换pi-1与pj
void swap(int& num1 ,int &num2)
{
int temp = num1;