- 主题:请教一个用迭代函数解决青蛙跳台阶的问题(带程序)
自己在自学C语言,在做青蛙跳台阶的习题的时候遇到困难了。不知道有没有高手能给指
点一二:
题目是这样的:
//一共有r级台阶,青蛙一次可以跳1~m(m介于1至r之间)级台阶,青蛙只能向上跳,且
最后一跳刚好跳到最上面一级台阶(不能跳过).
//问一共有多少种跳法?并且将所有跳法罗列出来。
//比如3级台阶,青蛙一次最多跳3级的跳法一共有4种:111;12;21;3
目前我的程序能正确算出总的跳法,但是数组记录各种跳法遇到困难了。
这是程序运行的结果:
4 级台阶一次最多跳 2 级的跳法一共 5 种:
1 1 1 1 1
2 2 0 0 0
3 2 1 0 0
4 2 1 1 0
5 2 0 0 0
实际应该是:
1 1 1 1 1
2 1 1 2 0
3 1 2 1 0
4 2 1 1 0
5 2 2 0 0
原因是函数在递归的时候,归的那一下不是归到最前,而是归到倒数第2个跳步,所以造
成目前这种状况。但是我自己也不知道该如何解决这个问题,请教一下高手,用递归方
法解此题的话,是不是没有办法记录全部的跳法?如果能解决该如何改呢?
源程序如下:
#include <stdlib.h>
#include <stdio.h>
int BZ=0;//全局变量,统计一共有多少种跳法,当剩余级数每1次变零,这个数加1
int I=0;//记录跳法的数组的行坐标
int J=1;//记录跳法的数组的列坐标,第1列记录第几种方法,所以从第2列开始记录
void FJ(int RS,int MS) //FJ:Frog Jump;RS:Remain Steps;MS:青蛙可以跳的最大步数,小于RS
{ int i;//青蛙每次可能跳的步数
for(i=1;i<=__min(RS,MS);i++) //第一次跳无需考虑跳的最大级数大于剩余阶数的问题
{
if (RS-i>0) //未跳尽剩余台阶
{ FJ(RS-i,MS);
}
else//跳尽剩余台阶了
BZ=BZ+1;
}
}
void FR(int **p,int RS,int MS) //RS:Remain Steps;MS:青蛙可以跳的最大步数,小于RS
//这个FR函数只为记录每一种跳法的各跳级数
{ int i;//青蛙每次可能跳的步数
for(i=1;i<=__min(RS,MS);i++) //第一次跳无需考虑跳的最大级数大于剩余阶数的问题
{
if (RS-i>0)//未跳尽剩余台阶
{
p[I][J]=i;
J=J+1;
FR(p,RS-i,MS);
}
else//跳尽剩余台阶了
{
p[I][J]=i;//记录跳尽时最后一跳的级数
I=I+1;//每次跳尽,记录完后就换行记录一种新的跳法
J=1;//每次跳尽,记录完后从头开始记录
}
p[I-1][0]=I;//数组第一列记录是第几种跳法
}
}
int main()
{
int r;
int m;
printf("请输入台阶级数后按下回车键:\n");
scanf("%d",&r);
printf("请输入青蛙一次最多能跳几级台阶:\n");
scanf("%d",&m);
FJ(r,m);//调用之前定义的函数
printf("%d 级台阶一次最多跳 %d 级的跳法一共 %d 种:\n",r,m,BZ);
//下面要记录 每一种跳法的各跳级数了
int **p;//准备通过二级指针创建全0二维数组,用于存放每一种跳法
int j;
p=(int**)calloc(BZ+1,sizeof(int*));
for(j=0;j<BZ+1;j++)
{
p[j]=(int*)calloc(r+1,sizeof(int));
}
FR(p,r,m); //调用填写函数,将每一种跳法存进数组
int i;
for(i=0;i<BZ;i++)//打印出所有跳法组合
{
for(j=0;j<r+1;j++)
{
printf("%4d",p[i][j]);
if ((j!=0)&(j%(r)==0) )
printf("\n");
}
}
}
--
修改:sqsl FROM 219.142.154.*
FROM 111.193.227.*
感谢大牛分享的算法,涨知识了
不知道有没有大牛帮忙看看我的算法是否有补救的可能?也是为了涨知识,谢谢!
【 在 z16166 的大作中提到: 】
: 这类不定方程问题的解法叫DFS(深度优先搜索),用数组记录搜索过的树上的路径
: const int r = 5;
: const int m = 3;
: ...................
--
FROM 111.193.227.*
#include <stdlib.h>
#include <stdio.h>
int BZ=0;//全局变量,统计一共有多少种跳法,当剩余级数每1次变零,这个数加1
int I=0;//记录跳法的数组的行坐标
int J=1;//记录跳法的数组的列坐标,第1列记录第几种方法,所以从第2列开始记录
void FJ(int RS,int MS) //FJ:Frog Jump;RS:Remain Steps;MS:青蛙可以跳的最大步数,小于RS
{ int i;//青蛙每次可能跳的步数
for(i=1;i<=__min(RS,MS);i++) //第一次跳无需考虑跳的最大级数大于剩余阶数的问题
{
if (RS-i>0) //未跳尽剩余台阶
{ FJ(RS-i,MS);
}
else//跳尽剩余台阶了
BZ=BZ+1;
}
}
void FR(int **p,int RS,int MS) //RS:Remain Steps;MS:青蛙可以跳的最大步数,小于RS
//这个FR函数只为记录每一种跳法的各跳级数
{ int i;//青蛙每次可能跳的步数
for(i=1;i<=__min(RS,MS);i++) //第一次跳无需考虑跳的最大级数大于剩余阶数的问题
{
if (RS-i>0)//未跳尽剩余台阶
{
p[I][J]=i;
J=J+1;
FR(p,RS-i,MS);
}
else//跳尽剩余台阶了
{
p[I][J]=i;//记录跳尽时最后一跳的级数
I=I+1;//每次跳尽,记录完后就换行记录一种新的跳法
J=1;//每次跳尽,记录完后从头开始记录
}
p[I-1][0]=I;//数组第一列记录是第几种跳法
}
}
int main()
{
int r;
int m;
printf("请输入台阶级数后按下回车键:\n");
scanf("%d",&r);
printf("请输入青蛙一次最多能跳几级台阶:\n");
scanf("%d",&m);
FJ(r,m);//调用之前定义的函数
printf("%d 级台阶一次最多跳 %d 级的跳法一共 %d 种:\n",r,m,BZ);
//下面要记录 每一种跳法的各跳级数了
int **p;//准备通过二级指针创建全0二维数组,用于存放每一种跳法
int j;
p=(int**)calloc(BZ+1,sizeof(int*));
for(j=0;j<BZ+1;j++)
{
p[j]=(int*)calloc(r+1,sizeof(int));
}
FR(p,r,m); //调用填写函数,将每一种跳法存进数组
int i;
for(i=0;i<BZ;i++)//打印出所有跳法组合
{
for(j=0;j<r+1;j++)
{
printf("%4d",p[i][j]);
if ((j!=0)&(j%(r)==0) )
printf("\n");
}
}
}
【 在 mango7788 的大作中提到: 】
: 能抽时间把你的程序缩进一下吗?
--
修改:sqsl FROM 219.142.154.*
FROM 219.142.154.*
我第2个函数几乎就是第1个翻版,只是调用一个数组存每一次跳了多少步。但是因为函
数迭代的结构,不是所有跳法都能记录齐全
我就是在学编程,遇到困难想解决
【 在 mango7788 的大作中提到: 】
: 刚才我回复的不见了。
: 你的第一个函数应该是对的,第二个太长了没有看。
: 我在你第一个函数里加了两行记录路径的。路径可以当参数传进来,我懒,就搞了全局的。
: ...................
--
FROM 111.193.227.*
是的,您分析的很对,我按这个思路去改一改看,成功了回来回复,不过今天有点忙,
可能搞不出来
【 在 mango7788 的大作中提到: 】
: 我没有看你打印的那部分code,但我可以直观的解释一下:
: 如果我们站在青蛙的角度,往回看我们上来的路径,就是要打印的信息。
: 当青蛙尝试另外一条路的时候,是把自己拉回了一个曾经经过的位置,重新跳。
: ...................
--
FROM 111.193.227.*
收到,谢谢,我目前先尝试用调整矩阵的方法来补齐缺失的步数,已经快成功了,完事
再按您说的方法试试。
【 在 z16166 的大作中提到: 】
: 有两处错误
: 1、(RS - i)和0比较是三种情况,不是两种。
: 你的代码会导致(RS - i) < 0这种无解的情况下,也会执行BZ = BZ + 1,这样解的总数BZ是错的。(但这个题里正好没有错)
: ...................
--
FROM 111.193.229.*
第1个问题,我前面有限定条件: for(i=1;i<=__min(RS,MS);i++)
且MS(单次最大跳跃级数)也是小于等于RS(台阶总数)的,所以不会出现小于0的情况
。
我程序最大的问题是下一次迭代和上一次迭代有部分重叠,只能记录部分步数,但是计
算一共有多少种跳法是准确的。
我试图调整那个记录矩阵也失败了,因为迭代的折叠规律比较复杂,不好用程序语言来
表达。
您这个程序我还在学习中
【 在 z16166 的大作中提到: 】
: 有两处错误
: 1、(RS - i)和0比较是三种情况,不是两种。
: 你的代码会导致(RS - i) < 0这种无解的情况下,也会执行BZ = BZ + 1,这样解的总数BZ是错的。(但这个题里正好没有错)
: ...................
--
FROM 111.193.229.*
您说的J复位到1的错误,我去更改了,思路就是不复位到1,只是减1,相当于从上一种
跳法的尾巴回缩1位,目前程序是对的了。因为我的对跳步约定了不允许大于剩余台阶,
所以也没有用到break语句,没有剪枝那一步。
但是我代码的执行效率偏低,比如20级台阶,最大2步的跳法
我要执行12秒,您那个只需要8秒。
不过我是执行了两次递归算法(函数FJ一次,函数FR一次),我如果只用函数FR,用re
alloc的方式按需扩充“储存数组”,不知道能不能快一些。
#include <stdlib.h>
#include <stdio.h>
int BZ=0;//全局变量,统计一共有多少种跳法,当剩余级数每1次变零,这个数加1
int I=0;//记录跳法的数组的行坐标
int J=1;//记录跳法的数组的列坐标,第1列记录第几种方法,所以从第2列开始记录
void FJ(int RS,int MS) //FJ:Frog Jump;RS:Remain Steps;MS:青蛙可以跳的最大步数,小于RS
{ int i;//青蛙每次可能跳的步数
for(i=1;i<=__min(RS,MS);i++) //第一次跳无需考虑跳的最大级数大于剩余阶数的问题
{
if (RS-i>0) //未跳尽剩余台阶
{
FJ(RS-i,MS);
}
else//跳尽剩余台阶了
BZ=BZ+1;
}
}
void FR(int **p,int RS,int MS) //RS:Remain Steps;MS:青蛙可以跳的最大步数,小于RS
//这个FR函数只为记录每一种跳法的各跳级数
{ int i;//青蛙每次可能跳的步数
int j;
for(i=1;i<=__min(RS,MS);i++) //第一次跳无需考虑跳的最大级数大于剩余阶数的问题
{
if (RS-i>0)//未跳尽剩余台阶
{
p[I][J]=i;
J=J+1;
FR(p,RS-i,MS);
//函数回归后,记录分叉点之后的新跳法
J=J-1;//因为尝试的跳法比上一次多1步,
//所以新一行的记录点从上一行的队尾回退1
//下面是把老跳法的前几步填补新跳法的分叉点之前
for(j=1;j<J;j++)
{
p[I][j]=p[I-1][j];
}
}
else//跳尽剩余台阶了
{
p[I][J]=i;//记录跳尽时最后一跳的级数
I=I+1;//每次跳尽,记录完后就换行记录一种新的跳法
}
p[I-1][0]=I;//数组第一列记录是第几种跳法
}
}
int main()
{
int r;
int m;
printf("请输入台阶级数后按下回车键:\n");
scanf("%d",&r);
printf("请输入青蛙一次最多能跳几级台阶:\n");
scanf("%d",&m);
//下面4行是避免输入错误
if (m==0)
printf("青蛙可跳跃的最大步数必须大于等于1\n");
else if (m>r)
m=r;
FJ(r,m);//调用之前定义的函数
printf("%d 级台阶一次最多跳 %d 级的跳法一共 %d 种:\n",r,m,BZ);
//下面要记录 每一种跳法的各跳级数了
int **p;//准备通过二级指针创建全0二维数组,用于存放每一种跳法
int j;
p=(int**)calloc(BZ+1,sizeof(int*));
for(j=0;j<BZ+1;j++)
{
p[j]=(int*)calloc(r+1,sizeof(int));//创建一级指针,多搞1列,
}
FR(p,r,m); //调用填写函数,将每一种跳法存进数组
int i;
int k;
int L7=r+1; //临时变量,打印到第几列
for(i=0;i<BZ;i++)//打印出所有跳法组合
{
for(j=0;j<L7;j++)
{
printf("%4d",p[i][j]);
if ((j!=0)&(j%(L7-1)==0) )
printf("\n");
}
}
}
【 在 z16166 的大作中提到: 】
: 有两处错误
: 1、(RS - i)和0比较是三种情况,不是两种。
: 你的代码会导致(RS - i) < 0这种无解的情况下,也会执行BZ = BZ + 1,这样解的总数BZ是错的。(但这个题里正好没有错)
: ...................
--
修改:sqsl FROM 111.193.229.*
FROM 111.193.229.*