马拦过河卒
Description
棋盘上A点有一个过河卒,需要走到目标B点。卒行走的规则:可以向下、或者向右。同时在棋盘上C点有一个对方的马,该马所在的点和所有跳跃一步可达的点称为对方马的控制点。因此称之为“马拦过河卒”。棋盘用坐标表示,A点(0,0)、B点(n,m)(n,m为不超过15的整数),同样马的位置坐标是需要给出的。现在要求你计算出卒从A点能够到达B点的路径的条数,假设马的位置是固定不动的,并不是卒走一步马走一步。
Input
一行四个数据,用空格分隔,分别表示B点的坐标和马的坐标。
Output
一个数据,表示所有的路径条数。
Sample
Input
6 6 3 3
Output
6
AC代码直通车
我们用题目题目中的数据进行讲解分析
1)首先我们会得到如下坐标分布:A点(0,0) B点(6,6) 马(3,3)
又因为B点坐标,n,m为不超过15 的整数,所以需要16*16的数组(我这里只画了15*15),map这个数组来记录每个坐标点能否通行(赋值1代表可以通行,0代表控制点不可以通行)
还需要另外一个数组来记录可以到达当前坐标点的路线数tripnum,也是16*16;
2)我们对map数组全部赋值为1,代表初始全部可以通行
for(int i=0;i<16;i++)
for(int j=0;j<16;j++)
map[i][j]=1;
3)然后对马的控制点赋值为0,代表不可通行。
这里涉及到一个马的控制点坐标的问题,可以用相对坐标来表示,玩过象棋的朋友都知道,“马走日”可以控制八个点,称作“八面威风”,也就是下面这八个点。
用两个数组来存他们与马坐标的相对位置坐标,相同下标组合成一组坐标,然后用马的坐标加上他们的相对坐标得到控制点的实际坐标
int a[9]={0,-1,-1,-2,-2,1,1,2,2};
int b[9]={0,2,-2,1,-1,2,-2,1,-1};
for(int i=0;i<9;i++)
{
if(x+a[i]<=15 && x+a[i]>=0 && y+b[i]<=15 && y+b[i]>=0) //判断是不是在map地图以内
map[x+a[i]][y+b[i]]=0;
}
4)因为卒只能向下向右运动,所以map数组中的第一行和第一列的坐标,只能是通过(0,0)直接到达,所以如果它们可以通行,那么到达此坐标的路线也只会是一条(这里想一下)
所以这里我们遍历map数组是否可以通行,如果可以则在tripnum数组记录下可以到达此坐标的路线数,对于第一行和第一列来说,当存在一个控制点的时候,那么控制点后面的肯定是无法到达的,所以直接break。
for(int i=0;i<16;i++)
{
if(map[0][i]==1)
{
tripnum[0][i]=1;
}
else
break;
}
for(int i=0;i<16;i++)
{
if(map[i][0]==1)
{
tripnum[i][0]=1;
}
else
break;
}
5)之前的都是铺垫,那么下面就是这个题的核心代码了
我们开始计算到达B点的所有路线。要想到达B点只能通过B点上方或左边的坐标,所以我们要计算到达一个点的路线总数的时候就要,把坐标点左边的路线数加上坐标点上边的路线数,这里就涉及到了递推的原理。
但是如果一个点是控制点的话,它也是可以到达的,具有到达路线数值,但是不可通行。所以进行计算可到达路线数时候,先判断一下是不是可通行点,如果是,则进行计算;如果不是,在保持初值0;
最后打印出tripnum[i][j]的值就可以了
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(map[i][j]==1)
tripnum[i][j]=tripnum[i-1][j]+tripnum[i][j-1];
}
}
完整AC代码
#include<iostream>
#include<cstdio>
using namespace std;
int main()
{
int a[9]={0,-1,-1,-2,-2,1,1,2,2};
int b[9]={0,2,-2,1,-1,2,-2,1,-1};
int map[16][16]={0};
long long tripnum[16][16]={0};
int n,m,x,y;
scanf("%d %d %d %d",&n,&m,&x,&y);
for(int i=0;i<16;i++)
for(int j=0;j<16;j++)
map[i][j]=1;
for(int i=0;i<9;i++)
{
if(x+a[i]<=15 && x+a[i]>=0 && y+b[i]<=15 && y+b[i]>=0)
map[x+a[i]][y+b[i]]=0;
}
for(int i=0;i<16;i++)
{
if(map[0][i]==1)
{
tripnum[0][i]=1;
}
else
break;
}
for(int i=0;i<16;i++)
{
if(map[i][0]==1)
{
tripnum[i][0]=1;
}
else
break;
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(map[i][j]==1)
tripnum[i][j]=tripnum[i-1][j]+
tripnum[i][j-1];
}
}
printf("%lld",tripnum[n][m]);
return 0;
}