基于递归求解方法的递归算法设计
当求解问题的方法是递归(如Hanoi问题)的或者可以转换成递归方法求解时(如皇后问题),可以设计成递归算法。
例如,求f(n)=1+2+…+n(n>=1),这个问题可以转化为递归方法求解,假设“小问题”是f(n-1)=1+2+…+(n-1),是可求得,则f(n)=f(n-1)+n。
对于采用递归方法求解的问题,需要对问题本身进行分析,确定大,小问题之间的关系,构造合理的递归体。
例:采用递归算法求解迷宫问题,并输出从入口到出口的所有迷宫路径。
解:迷宫问题:求从(xi,yi)到(xe,ye)的迷宫路径,用path变量保存一条迷宫路径,其中Pathtype类型的声明如下:
typedef struct
{
int i; //当前方块的行号
int j; //当前方块的列号
} Box;
typedef struct
{
Box data[MaxSize];
int length; //路径长度
} PathType; //定义路径类型
int count=0; //存放迷宫路径的条数
当从(xi,yi)方块找到一个相邻的可走方块(i,j)后,mgpath(i,j,xe,ye,path)表示求从(i,j)到出口(xe,ye)的迷宫路径。显然,mgpath(xi,yi,xe,ye,path)是“大问题”,而mgpath(i,j,xe,ye,path)是“小问题”(即大问题=试探一步+小问题)。求解上述迷宫问题的递归模型如下:
mgpath(xi,yi,xe,ye,path)==将(xi,yi)添加到path中;输出path中的迷宫路径; 若(xi,yi)==(xe,ye)即找到出口 mgpath(xi,yi,xe,ye,path)==是对于(xi,yi)四周的每一个相邻方块(i,j): 若(xi,yi)不是出口可走。 ①:将(xi,yi)添加到path中; ②:mg[xi][yi]=-1; ③:mgpath(i,j,xe,ye,path); ④:path回退一步并置mg[xi][yi]=0; mgpath(xi,yi,xe,ye,path)==不做任何事情; 若(xi,yi)不是出口且不可走。
在上述模型中,当完成“小问题”mgpath(xi,yi,xe,ye,path)后将path回退并置mg[xi][yi]为0(对应④),其目的是恢复前面求迷宫路径而改变的环境,以便找出所有的迷宫路径。对应的递归算法如下:
#include <stdio.h>
#define MaxSize 100
#define M 4
#define N 4
int mg[M+2][N+2]=
{ {1, 1, 1, 1, 1, 1},
{1, 0, 0, 0, 1, 1},
{1, 0, 1, 0, 0, 1},
{1, 0, 0, 0, 1, 1},
{1, 1, 0, 0, 0, 1},
{1, 1, 1, 1, 1, 1}
};
typedef struct
{
int i; //当前方块的行号
int j; //当前方块的列号
} Box;
typedef struct
{
Box data[MaxSize];
int length; //路径长度
} PathType; //定义路径类型
int count=0; //存放迷宫路径的条数
int main()
{
PathType path;
path.length=0; //初始化路径长度
mgpath(1,1,M,N,path);
return 1;
}
void mgpath(int xi,int yi,int xe,int ye,PathType path)
//求解路径为:(xi,yi)->(xe,ye)
{
int di,k,i,j;
if (xi==xe && yi==ye) //找到了出口,输出路径
{
path.data[path.length].i = xi;
path.data[path.length].j = yi;
path.length++;
printf("迷宫路径%d如下:\n",++count);
for (k=0;k<path.length;k++)
printf("\t(%d,%d)",path.data[k].i,path.data[k].j);
printf("\n");
}
else //(xi,yi)不是出口
{
if (mg[xi][yi]==0) //(xi,yi)是一个可走方块
{
di=0;
while (di<4) //找(xi,yi)的一个相邻方块(i,j)
{
switch(di)
{
case 0:i=xi-1; j=yi; break;
case 1:i=xi; j=yi+1; break;
case 2:i=xi+1; j=yi; break;
case 3:i=xi; j=yi-1; break;
}
path.data[path.length].i = xi;
path.data[path.length].j = yi;
path.length++;
mg[xi][yi]=-1; //避免重复找路径
mgpath(i,j,xe,ye,path);
path.length--; //回退一个方块
mg[xi][yi]=0; //恢复(xi,yi)为可走
di++;
}
}
}
}