LFYZ-OJ ID: 1020 过河卒(NOIP2002)

过河卒

Proble Description

如图,A 点有一个过河卒,需要走到目标 B 点。卒行走规则:可以向下、或者向右。同时在棋盘上的任一点有一个对方的马(如上图的C点),该马所在的点和所有跳跃一步可达的点称为对方马的控制点。例如上图 C 点上的马可以控制 9 个点(图中的P1,P2 … P8 和 C)。卒不能通过对方马的控制点。

棋盘用坐标表示,A 点(0,0)、B 点(n,m)(n, m 为不超过 20 的整数,并由键盘输入),同样马的位置坐标是需要给出的(约定: C不等于A,同时C不等于B)。现在要求你计算出卒从 A 点能够到达 B 点的路径的条数。1<=n,m<=15

INPUT

B点的坐标(n,m)以及对方马的坐标(X,Y){不用判错}

OUTPUT

一个整数(路径的条数)

Sample Input

6 6 3 2

Sample Output

17

分析

到达棋盘上的任意一点只有两条路:从上方,从左方。因此到达(n, m)点的路径数R(n, m)=R(n-1, m)+R(n, m-1),这就成了一个递推问题,递推的起点就是A点(0, 0)。整理一下,已知条件和递推规则如下:

  • 第0行,R(0, m)=R(0, m-1)
  • 第0列,R(n, 0)=R(n-1, 0)
  • 马可控点,R(n, m)=0
  • 其它,R(n, m)=R(n-1, m)+R(n, m-1)
  • 已知条件:R(0, 0)=1

这样,可把棋盘用一个二维数组来表示。一行一行扫描数组的每个元素进行计算,最终可推算出R(n, m)

代码示例

#include<iostream>
using namespace std;
int M[20][20];									//棋盘 
int main(){
	int n, m, X, Y; 
	scanf("%d%d%d%d", &n, &m, &X, &Y);
	for(int i=0; i<=n; i++)						//A点到B点之间的节点全部初始化为-1 
		for(int j=0; j<=m; j++)
			M[i][j]=-1;
												//马可控制点设置为0条路径 
	M[X][Y]=M[X-2][Y-1]=M[X-2][Y+1]=M[X-1][Y-2]=M[X-1][Y+2]=
			M[X+2][Y-1]=M[X+2][Y+1]=M[X+1][Y-2]=M[X+1][Y+2]=0;
	M[0][0]=1;									//递推起点 
	for(int i=0; i<=n; i++)
		for(int j=0; j<=m; j++){
			if(i==0 && j==0) 		continue;	//起点跳过 
			if(M[i][j]==0)			continue;	//马可控点跳过 
			if(i==0)		M[i][j]=M[i][j-1];
			else if(j==0)	M[i][j]=M[i-1][j];
			else  M[i][j]=M[i-1][j]+M[i][j-1];
		}
	printf("%d", M[n][m]);
} 
posted @ 2017-05-18 22:56  LFYZOI题解  阅读(594)  评论(0编辑  收藏  举报