递推----过河卒问题
首先,让我们先来了解一下有关二维数组的语法
1.如何定义二维数组:
类型 数组名[长度1][长度2];
esp.:int a[3][3];
2.赋值:
数组名[长度1][长度2]=值;
或者在定义的时候进行赋值:
数组名[长度1][长度2]={{值,值},{值,值}…};
esp::int a[2][2]={{1,2},{3,4}};或: a[3][3]=5;
3.输出:
以整形数组为例
printf("%d",a[3][3]);
现在在让我们来看一个经典的问题:
*A点有一个过河卒 需要走到目标B点,它只能向下或者向右移动
在棋盘中的任意一个点上有对方的马,记为C点,马所在的点和所有跳跃一步可达的点称为对方马的控制点,小卒不能通过马的控制点
现给定A点位置(0,0),B(m,n)(m,n<=20),C(x,y)且C不与A,B重叠
计算出小卒从A顺利到达B的路径条数
输入:B点坐标(n,m)以及对方马C的坐标(x,y) (马的坐标一定在棋盘范围内,但可能落在边界上)
输出: 小卒从A点到B点的路径条数
输入样例:6 6 3 2
输出样例:17
*首先想到,在遇到横向和纵向两个维度的数据时,应当使用二维数组
从A点到B点的路径受两个因素影响:
1.小卒本身的行走规则
2.马及其控制点的影响
先不考虑马的存在,只分析小卒的行走路径:
用数字表示出,当B在该位置的时候,A到B的路径条数,如下图所示:
会发现,当前点的路径条数=左边路径条数+上边路径条数
这里有一个特殊情况:
下标为0的行没有上边的路径,故等于其左边的值
下标为0的列没有左边的路径,故等于上边的值
因此,可以创建一个二维数组a[21][21](数组空间要比20大一点),来存储行和列
注意,前边已经说过,不要忘记初始化数组
当行为0,纵为0的时候,只有一条路径(排除B与A点重合的情况)
再考虑有马存在的时候
马及其控制点的位置,小卒不能通过,故需要标记马及其控制点的位置
具体操作方式可以为:
将A,B之前的格全部初始化为1,将马及其控制点标记为0,通过判断是1还是0来判断是否为马的控制点,从而判断马是否挡路
还有一个条件需要判断:马及其控制点是否在A与B中间,若不在,则以上所有不需要去考虑(因为小卒只能向右和下走)
分析完毕,下面是代码
#include <iostream>
using namespace std;
int main(){
int a[21][21]={0};
int m,n,x,y;
cin>>m>>n>>x>>y;
for(int i=0;i<=m;i++){
for(int k=0;k<=n;k++){
a[i][k]=1;
}
}
//如果在AB范围内,标记为0
if(x-1>=0&&y-2>=0) a[x-1][y-2]=0;//P1
if(x+1<=m&&y-2>=0) a[x+1][y-2]=0;//P2
if(x+2<=m&&y-1>=0) a[x+2][y-1]=0;//P3
if(x+2<=m&&y+1<=n) a[x+2][y+1]=0;//P4
if(x+1<=m&&y+2<=n) a[x+1][y+2]=0;//P5
if(x-1>=0&&y+2<=n) a[x-1][y+2]=0;//P6
if(x-2>=0&&y+1<=n) a[x-2][y+1]=0;//P7
if(x-2>=0&&y-1>=0) a[x-2][y-1]=0;//P8
//还要考虑马所在的点
a[x][y]=0;
for(int i=0;i<=m;i++){
for(int k=0;k<=n;k++){
//A与B重合时
if(i==0&&k==0) continue;
//避开马及其控制点
if(a[i][k]==0) continue;
//在行为0,和纵为0的地方
if(i==0){
a[i][k]=a[i][k-1];
}else if(k==0){
a[i][k]=a[i-1][k];
}else a[i][k]=a[i][k-1]+a[i-1][k];
}
}
cout<<a[m][n];
return 0;
}
END…
ps:国庆假期第三天了
“我想,放假的意义就在于:一个说不起就不起的早晨、一个说不睡就不睡的深夜和一个说不出门就不出门的白天;又或者是满怀期待地去想见的人,去奔赴山海,去做梦,去闲着。”
愿大家都能享受自己的假期~