习题解答

练习解答1、求1+2+3+……+n的值

求m+(m+1)+(m+2)+ +n的值

int sum(int n)

{ if(n==1)

return 1;

else

return n+sum(n-1);

}

int main(int argc, char *argv[])

{ int n,s=0;

printf("input n\n");

scanf("%d",&n);

s=sum(n);

printf("%d",s);

system("pause");

return 0;

}

//1求m+(m+1)+(m+2)+ +n的值

int sum(int m,int n)

{ if(n==m)

return m;

else

return n+sum(m,n-1);

}

int main(int argc, char *argv[])

{ int n,m,s=0;

printf("input m(begin)\n");

scanf("%d",&m);

printf("input n(end)\n");

scanf("%d",&n);

s=sum(m,n);

printf("%d",s);

system("pause");

return 0;

}

2、求1*2*3*……*n的值

int mul(int n)

{if (n==1)

return 1;

else

return n*mul(n-1);

}

int main(int argc, char *argv[]) {

int n,s=0;

printf("input n\n");

scanf("%d",&n);

s=mul(n);

printf("result=%d",s);

system("pause");

return 0;

}

*/

//2求m*(m+1)*(m+2)*…*n的值

int mul(int m,int n)

{if (n==m)

return m;

else

return n*mul(m,n-1);

}

int main(int argc, char *argv[]) {

int n,m,s=0;

printf("input m\n");

scanf("%d",&m);

printf("input n\n");

scanf("%d",&n);

s=mul(m,n);

printf("result=%d",s);

system("pause");

return 0;

}

3、小猴子第一天摘下若干桃子,当即吃掉一半,又多吃一个.第二天早上又将剩下的桃子吃一半,又多吃一个.以后每天早上吃前一天剩下的一半另一个.到第10天早上猴子想再吃时发现,只剩下一个桃子了.问第一天猴子共摘多少个桃子?

解答:相邻两天桃子个数的关系

前一天a 后一天b=a/2-1 所以a=2*(b+1)

int fruit(int sum,int day)

{ if(day==1)

return sum;

else

return fruit((sum+1)*2,day-1);

}

int main(int argc, char *argv[])

{

int s=fruit(1,10);

printf("sum=%d",s);

system("pause");

return 0;

}

4、一个人赶着鸭子去每个村庄卖,每经过一个村子卖去所赶鸭子的一半又一只。这样他经过了七个村子后还剩两只鸭子,问他出发时共赶多少只鸭子?经过每个村子卖出多少只鸭子?

int duck(int sum,int day)

{ if(day==1)

return sum;

else

return duck((sum+1)*2,day-1);

}

int main(int argc, char *argv[])

{

int s=duck(2,7);

printf("sum=%d",s);

for(int day=1;day<=7;day++)

{ printf("sell=%d, ",s/2+1);

s=s/2-1;

}

return 0;

}

5、求两个数的最大公约数。

int maxFactor(int m,int n)

{

if (n==0)

return m;

else

return maxFactor(n,m%n);

}

int main(int argc, char *argv[]) {

int m,n,t;

printf("input m and n \n");

scanf("%d %d",&m,&n);

int r=maxFactor(m,n);

printf("result=%d",r);

return 0;

}

6、求两个数的最小公倍数。

X和Y的最小公倍数=X*Y / (X和Y的最大公约数)

int maxFactor(int m,int n)

{static int c=m*n; //静态变量,第一次调用时执行分配空间的操作

if (n==0)

return c/m;

else

return maxFactor(n,m%n);

}

int main(int argc, char *argv[]) {

int m,n,t;

printf("input m and n \n");

scanf("%d %d",&m,&n);

int r=maxFactor(m,n);

printf("result=%d",r);

return 0;

}

7、输入一个数,求这个数的各位数字之和。

int add(int s)

{ if (s<10)

return s;

else

return s%10+add(s/10);

}

int main(int argc, char *argv[]) {

int a,b;

printf("input data\n");

scanf("%d",&a);

b=add(a);

printf("result=%d",b);

return 0;

}

8、角谷定理。输入一个自然数,若为偶数,则把它除以2,若为奇数,则把它乘以3加1。经过如此有限次运算后,总可以得到自然数值1。求经过多少次可得到自然数1。

如:输入22,

输出 22 11 34 17 52 26 13 40 20 10 5 16 8 4 2 1

STEP=16

int i = 1;

int jg(int n)

{

if(n == 1)

{printf("%d",n);

return i;

}

else if(n%2 == 0)

{ printf("%d,",n);

jg(n/2);

i++;

}

else

{printf("%d,",n);

jg(n*3+1);

i++;

}

}

int main(int argc, char* argv[])

{ int n,step;

printf(" input the num:");

scanf("%d",&n);

step = jg(n);

printf("\nStep = %d\n",step);

return 0;

}

9、将十进制转换为二进制。

/*//十进制转二进制

9/2=4--------1

4/2=2--------0

2/2=1--------0

9==1001

*/

int jz(int num)

{ if(num == 1)

{printf("%d",num);

return 0;

}

jz(num/2);

printf("%d",num%2);

}

int main(int argc, char* argv[])

{ int num;

printf("please input the num:");

scanf("%d",&num);

jz(num);

printf("\n");

return 0;

10、设有n个数已经按从大到小的顺序排列,现在从键盘上输入x,判断它是否在这n 个数中,如果存在则输出“yes”否则输出“no”。

const int n=5;

int a[n],x;

void search(int x,int top,int bot)

{int mid;

if (top<=bot)

{ mid=(top+bot)/2;

if (x==a[mid])

printf("YES,%d is pos %d",x,mid);

else if (x

search(x,top,mid-1);

else

search(x,mid+1,bot);

}

else

printf("NO,it is not here");

}

int main(int argc, char *argv[]) {

printf("input array\n");

for(int k=0;k

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;

}

相关文档
最新文档