现在的位置: 首页 > 综合 > 正文

马拦过河卒(NOIP2002)

2013年08月05日 ⁄ 综合 ⁄ 共 2709字 ⁄ 字号 评论关闭

 

马拦过河卒(NOIP2002)

(2010-05-14 15:57:22)

标签:

递归

杂谈

分类:
递归与回

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点的路 径的条数。

Input

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

Output

一个整数(路径的条数)。

Sample Input
6 6 3 2

 

Sample Output
17

 方法一:用回溯的方法:(分析略,见跳马)

马拦过河卒(NOIP2002)马拦过河卒(NOIP2002)Code
 1//马拦过河卒(NOIP2002)
 2program guoheju;
 3const
 4    dx:array[1..8of integer=(-2,-1,1,2,2,1,-1,-2);
 5    dy:array[1..8of integer=(1,2,2,1,-1,-2,-2,-1); //马控制的8个
 6
 7方向
 8var
 9    n,m,x,y,i,j,ans:longint;
10    g:array[0..20,0..20of 0..1//描述棋盘上的点是否受马控制
11
12procedure init;
13begin
14    readln(n,m,x,y);
15    g[x,y]:=1;
16    ans:=0;
17    for i:=1 to 8 do
18        if(x+dx[i]>=0)and(x+dx[i]<=n)
19        and(y+dy[i]>=0)and(y+dy[i]<=m) then
20            g[x+dx[i],y+dy[i]]:=1  //计算存储马的控制点
21end;
22
23procedure try(x,y:integer); //x,y为卒当前所在的位置
24begin
25    if(x=n)and(y=m) then ans:=ans+1  //到达目标
26    else
27    begin
28        if(y<m)and(g[x,y+1]=0then try(x,y+1); //向右走
29        if(x<n)and(g[x+1,y]=0then try(x+1,y); //向下走
30    end;
31end;
32
33begin
34    init;
35    try(0,0);
36    writeln(ans);
37end.

 

方法二:用递推的方法:
      当m,n比较小的时候,运用回溯可以求出解,但当m、n比较大的时候,就会超时。
      仔细观察,要到达棋盘上的任意一点,只能从左边和上边两个方向过来。因此,要到达某一点的路径数,等于和它相邻的左、上两个点的路径数和:F[i,j] = F[i-1,j] + F[i,j-1]。所以我们可以使用逐列(或逐行)递推的方法来求出从起始顶点到重点的路径数目,即使有障碍(我们将马的控制点称为障碍),这一方法也完全适用,只要将到达该点的路径数目置为0即可,用F[i,j]表示到达点(i,j)的路径数目,g[i,j]表示点(i, j)有无障碍,递推方程如下:
        F[0,0] = 1                              //起点
        F[i,0] = F[i-1,0]        {i > 0, g[x,y] = 0}//左边界
        F[0,j] = F[0,j-1]        {j > 0, g[x,y] = 0}//上边界
                      F[i,j] = 0            { g[x,y] = 1 }  //障碍点
         F[i,j] = F[i-1,j] + F[i,j-1]  {i > 0, j > 0, g[x, y] = 0}//递推式

与动态规划相比较,本题不是求最优值,在阶段中不做决策。

为了输出路径数量够大,采用数据类型为comp

马拦过河卒(NOIP2002)马拦过河卒(NOIP2002)Code
 1//马拦过河卒(NOIP2002)递推
 2program guoheju02;
 3const
 4    dx:array[1..8of integer=(-2,-1,1,2,2,1,-1,-2);
 5    dy:array[1..8of integer=(1,2,2,1,-1,-2,-2,-1);
 6var
 7    n,m,x,y,i,j:integer;
 8    g:array[0..20,0..20of integer;
 9    f:array[0..20,0..20of comp;  //数据类型避免使用高精度
10
11procedure init;
12begin
13    readln(n,m,x,y);
14    fillchar(g,sizeof(g),0);
15    g[x,y]:=1;
16    for i:=1 to 8 do
17        if(x+dx[i]>=0)and(x+dx[i]<=n)
18        and(y+dy[i]>=0)and(y+dy[i]<=m) then
19            g[x+dx[i],y+dy[i]]:=1;
20end;
21
22procedure main;
23begin
24    f[0,0]:=1   //起点
25    for i:=1 to do
26        if g[i,0]=0 then f[i,0]:=f[i-1,0];//左边界
27    for j:=1 to do
28        if g[0,j]=0 then f[0,j]:=f[0,j-1];//上边界
29    for i:=1 to do
30        for j:=1 to do
31            if g[i,j]=0 then
32                f[i,j]:=f[i-1,j]+f[i,j-1];
33end;
34
35begin
36    init;
37    main;
38    writeln(f[n,m]:0:0);//注意输出格式
39end.

抱歉!评论已关闭.