scanf("%d",&a[k]);
printf("input X\n");
scanf("%d",&x);
search(x,0,n-1);
return 0;
}
11、
基本形式:D[1]=0;d[2]=1
递归式:d[n]= (n-1)*( d[n-1] + d[n-2])
12、楼梯有N级台阶,上楼可以一步上一级,也可以一步上两级,请编一递归程序,打印出所有从第1级上到第N级的走法。提示:S(N)=S(N-1)+S(N-2)。递归的形式:s[n]=s[n-1]+s[n-2] 基本式子:s[1]=1;s[2]=2
/* //-----------------------只是输出总共几种方案,不打印每个方案-------------------------------
int trace(int n)
{
if(n==1)
{return 1;}
else if(n==2)
{return 2; }
else
{return trace(n-1)+ trace(n-2); }
}
int main()
{
int num;
printf("输入阶梯数:\n");
scanf("%d", &num);
printf("共有有%d种方法.\n", trace(num));
return 0;
}
*/
//--------------------------------可以输出每种方案-------------------------------------------
int a[101],n,passed,sum=0;
//passed,记录阶梯数目,sum记录方案数目,step记录迈脚的步数
void trace(int step)
{int i;
if(passed==n)
{sum++;
printf("第%d种方案:",sum);
for(i=1;i<=step-1;i++)
printf("%d,",a[i]);
printf("\n");
}
else
{for(i=1;i<=2;i++)
if(passed+i<=n)
{
a[step]=i;
passed+=i;
trace(step+1);
passed-=i;
}
}
}
int main(int argc, char *argv[]) { printf("请输入阶梯数n\n"); scanf("%d",&n); passed=0; trace(1); return 0; }
13、
编一递归程序,求组合数m
n C 。
已知:1
11---+=m n m n m n C C C
#include using namespace std;
#include "stdio.h"
/*//--------------------------------只计算有多少种组合---------------- int n,m;
int c(int n,int m) {
if(m<0||n<0||n每一步走法都有两种选择,或上一级或上两级,于是可以画出一个上楼梯方法的树形图示。如图所示是走3步时的情况
树中的每一个分支表示走上楼梯的一种走法,如果每一步都有两种选择,走n 步,将有2n
个分支!但是,按题目要求,每一步能否有两种选择是有限制的: 1.走到n 级台阶,就结束上楼;
2.如果剩余台阶数不足走1或2,就不能走。
于是,当n=3时,图中有若干分支是不符合要求的,将其剪枝,图中画×的枝条就是被剪断处。这样,满足条件的分支上的结点连起来就是:1-1-1,1-2,2-1三种走法方案。
从起点出发,每一步试探两种选择,能走就走,不能走,就退回一步,走另外一个分之。所有情况都试探过了,也就找到了所有方案。
× ×
× ×
×
× 开始
1
2
1
2
1
2
1
2 1
2 1 2 1
2
return 0;
if (m==1)
return n;
if (m==n)
return 1;
else
return c(n-1,m)+c(n-1,m-1);
}
int main()
{ cout<<"input n and m"<cin>>n>>m;
cout<<"一共有:"<}
*/
//----------------- 打印出每一种组合,在1-n之间的数字进行选择--------------------
# define MAXN 100
int a[MAXN];
int counts=0;
void comb(int n,int m)
{ int i,j;
for(i=n;i>=m;i--)
{ a[m]=i;
if(m>1)
comb(i-1,m-1);
else
{ counts++;
for(j=a[0];j>0;j--)
printf("%4d",a[j]);
printf("\n");
}
}
}
int main()
{ int n,m;
cout<<"input n"<cin>>n;
cout<<"input m"<cin>>m;
counts=0;
a[0]=m;
comb(n,m);
cout<<"一共有:"<return 0;
}
/*//---------打印出每一种组合,在任意数字间选择------------------
void combine(int a[], int n, int m, int b[], int M)
{ //a 存放候选数字,n 总项数,m 取出项数,b 存放选出结果,M = m最初始的值
int i, j;
for (i=n;i>= m;i--)
{ b[m-1] =i-1;
if (m > 1)
combine(a,i-1, m-1, b, M);
else
{ for(j=M-1; j>=0;j--)
printf("%d ", a[b[j]]);
printf("\n");
}
}
}
int main(void)
{int i;
int a[MAX], b[MAX];
// for(i=1; i<100; i++)//输入若干数字,用来备选
// a[i-1]=i;
a[0]=8;
a[1]=6;
a[2]=9;
a[3]=2;
a[4]=4;
combine(a,5,3,b,3);//5个数中选3个
}
*/
a[3] a[2] a[1] a[0]
n=5,m=3(i=5)5 3
n=4,m=2(i=4) 5 4
n=3,m=1(i=3) 5 4 3输出5,4,3
n=3,m=1 (i=2) 5 4 2输出5,4,2
n=3,m=1 (i=1) 5 4 1输出5,4,1 返回到循环n=4,m=2 (i=3) 5 3 1
n=2,m=1(i=2) 5 3 2输出5,3,2
n=2,m=1 (i=1) 5 3 1输出5,3,1 返回到循环n=4,m=2 (i=2) 5 2 1
n=1,m=1(i=1) 5 2 1 输出5,2,1 返回到上一层
因i--n=5,m=3 (i=4)4 2 1
n=3,m=2(i=3) 4 3 1
n=2,m=1(i=2) 4 3 2 输出4,3,2
n=2,m=1(i=1) 4 3 1 输出4,3,1 返回循环n=3,m=2(i=2) 4 2 1
n=1.m=1(i=1) 4 2 1 输出4,2,1 返回到上一层
因i--n=5,m=3 (i=3) 3 2 1
n=2,m=2(i=2) 3 2 1
n=1,m=1(i=1) 3 2 1 输出3,2,1 返回上一层
因i--n=5,m=3(i=2)循环结束
14、一个凸N边形,通过N边形内部互不相交的对角线,把N边形拆分成若干个三角形,不同
拆分方案的数目用H(N)表示。已知递归函数如下:
H(N+1)=H(2)*H(N)+H(3)*H(N-1)+……+H(N)*H(2),(为什么?)
H(2)=1。
请编写计算H(N)的递归程序。
三边形N (3)=H(2+1)=H(2)*H(2)=1*1=1
四边形N(4)=H(3+1)=H(2)*H(3)+H(3)*H(2)=1*1+1*1=2
五边形N(5)=H(4+1)=H(2)*H(4)+H(3)*H(3)+H(4)*H(2)=1*2+1*1+2*1=5
#include
using namespace std;
int h(int n)
{int i,j;
if(n==2)
return 1;
else
{
j=0;
for(i=2;i<=n-1;i++)
j=j+h(i)*h(n+1-i);
return j;
}
}
int main()
{ int a;
cout<<"请输入边数"<cin>>a;
cout<<"划分的方案数是"<return 0;
}
15、阿克曼函数(ACKMANN)A(X,Y)中,X、Y定义域是非负整数,函数值定义为:
A(X, Y)=Y+1 (X=0)
A(X, 0)=A(X-1,1)(X>0, Y =0)
A(X, Y)=A(X-1,A(X,Y-1))(X, Y>0)
设计一个递归程序,求A(X,Y)。
#include
using namespace std;
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
int count=0;
long a(int x,int y)
{ count++;
if (x==0)
return y+1;
else
{if (y==0)
return a(x-1,1);
else
return a(x-1,a(x,y-1));
}
}
int main()
{int X,Y;
cout<<"input X and Y"<cin>>X>>Y;
cout<<"结果是"<< a(X,Y);
cout<<",递归次数"<return 0;
}
16、某人写了N封信和N个信封,结果所有的信都装错了信封。求共有多少种情况。提示:
D(N)=(N-1)*(D(N-1)+D(N-2)),
D(1)=0,D(2)=1。为什么?
错排公式
D(n)表示当n个编号元素放在n个编号位置,编号与位置编号各不对应的方法数,那么D(n-1)就表示n-1个编号元素放在n-1个编号位置,编号与维族各不对应的方法数,其它类推.
第一步,把第n个元素放在一个错误的位置,比如位置k,一共有n-1种方法;
第二步,放编号为k的元素,这时有两种情况:
(1)把它放到位置n,由于第k个元素放到了位置n,元素n和k的位置都确定了,那么对于剩下的n-2个元素错排方法就有D(n-2)种;
(2)第k个元素不把它放到位置n,这时只有元素n的位置是确定的,剩下的n-1个元素,有D(n-1)种错排方法;
综上得到
D(n) = (n-1) [D(n-2) + D(n-1)]
特殊地,D(1) = 0, D(2) = 1.
#include
using namespace std;
int D(int n)
{
if ((n==1)||(n==2))
return n-1;
else
return (n-1)*(D(n-1)+D(n-2));
}
int main()
{ int n;
cout<<"请输入n "<cin>>n;
cout<<"结果是"<return 0;
}
17、编写一个程序,生成1,2,3,4,5五个数字的全排列。
#include
#include
using namespace std;
int count=0;
void permutation(int array[], int begin, int end)
{
int i,temp;
if(begin == end){
for(i = 0; i <= end; ++i)
{printf("%d ",array[i]);
}
printf("\n");
count++;
return;
} else {
//for循环遍历该排列中第一个位置的所有可能情况
for(i = begin; i <= end; ++i)
{
{temp=array[i];array[i]=array[begin];array[begin]=temp;}//swap(array[i], array[begin]);
//依次将1,2,3......n放到第一个位置permutation(array, begin + 1, end);
{temp=array[i];array[i]=array[begin];array[begin]=temp;} //swap(array[i], array[begin]);
//第一个swap进行了交换,现在还原位置,进行下一次递归}
}
}
int main(int argc, char **argv)
{
int a[5]={1,2,3,4,5};
permutation(a, 0, sizeof(a) / sizeof(int) - 1);
// char a[5] = {'a', 'b', 'c', 'd','e'};
// permutation(a, 0, sizeof(a) / sizeof(char) - 1);
printf("共有%d种",count);
return 0;
}
/*//-------------------C++语言,std空间有swap函数,可以用模板-------------------------- template
int count=0;
void permutation(T array[], int begin, int end)
{
int i;
if(begin == end){
for(i = 0; i <= end; ++i){
cout<}
cout<count++;
return;
} else {
//for循环遍历该排列中第一个位置的所有可能情况
for(i = begin; i <= end; ++i) {
swap(array[i], array[begin]);
permutation(array, begin + 1, end);
swap(array[i], array[begin]);
}
}
}
int main(int argc, char **argv)
{
char a[4] = {'a', 'b', 'c', 'd'};
permutation(a, 0, sizeof(a) / sizeof(char) - 1);
int a[4]={1,2,3,4;}
permutation(a, 0, sizeof(a) / sizeof(int) - 1);
cout<<"种数为"<return 0;
}
*/
例如排列1234
1。先保持1不动,排列234
2。保持2不动,排列34
3。保持3不动,排列4
4。得到4;输出1234。
5。然后跳转到3,将3与4互换,
6。得到3;输出1243。
7。跳转到2,将2与3互换,
8。重复3-6,得1324,1342。
9。跳转到2,将2与4互换,得到1423,1432。
以此类推
最后就得到全排列
//-----------------------------stl-------------------------------
#include
int num=0;
void permutation(int array[], int len)
{
sort(array, array + len);
do{
for(int i = 0; i < len; ++i){
cout<}
cout<num++;
}while(next_permutation(array, array + len));
}
int main(int argc, char **argv)
{
int a[5] = {1, 2, 3, 4,5};
permutation(a, sizeof(a) / sizeof(int));
printf("一共种数有%d",num);
return 0;
}
STL有一个函数next_permutation(),它的作用是如果对于一个序列,存在按照字典排序后这个排列的下一个排列,那么就返回true且产生这个排列,如果排列已经是字典逆序了,那就不存在下一个序列了,返回false。
设3 6 4 2为pn,下一个序列pn+1应该是4 2 3 6。观察第一个序列可以发现pn中的6 4 2已经为减序,在这个子集中再也无法排出更大的序列了,因此必须移动3的位置且要找一个数来取代3的位置。在6 4 2中6和4都比3大,但6比3大的太多了,只能选4。将4和3的位置对调后形成排列4 6 3 2。注意,由于4和3大小的相邻关系,对调后产生的子集6 3 2仍保持逆序,即该子集最大的一种排列。而4是第一次移动到头一位的,需要后面的子集为最小的排列,因此直接将6 3 2倒转为2 3 6便得到了正确的一个序列pn+1。
18、编写一个程序,生成1,2,3,4,5,6六个数字中任选出四个数字的全排列。
此题跟17题全排列类似,如果剩余的元素#include
int count=0;
int n=6,r=4;
void permutation(int array[], int begin, int end)
{
int i,temp;
if(begin== end-(n-r))
{
for(i = 0; i<=end-(n-r); ++i)
{printf("%d ",array[i]);
}
printf("\n");
count++;
return;
} else {
//for循环遍历该排列中第一个位置的所有可能情况
for(i = begin; i <= end; ++i)
{
{temp=array[i];array[i]=array[begin];array[begin]=temp;}//swap(array[i], array[begin]);
//依次将1,2,3......n放到第一个位置permutation(array, begin + 1, end);
{temp=array[i];array[i]=array[begin];array[begin]=temp;} //swap(array[i], array[begin]);
//第一个swap进行了交换,现在还原位置,进行下一次递归}
}
}
int main(int argc, char **argv)
{
int a[6]={1,2,3,4,5,6};
permutation(a, 0, sizeof(a) / sizeof(int) - 1);
// char a[6] = {'a', 'b', 'c', 'd','e','f'};
// permutation(a, 0, sizeof(a) / sizeof(char) - 1);
printf("共有%d种",count);
return 0;
}