马拦过河卒
Time Limit: 3000 ms Memory Limit: 65536 KiB
Problem Description
棋盘上A点有一个过河卒,需要走到目标B点。卒行走的规则:可以向下、或者向右。同时在棋盘上C点有一个对方的马,该马所在的点和所有跳跃一步可达的点称为对方马的控制点。因此称之为“马拦过河卒”。棋盘用坐标表示,A点(0,0)、B点(n,m)(n,m为不超过15的整数),同样马的位置坐标是需要给出的。现在要求你计算出卒从A点能够到达B点的路径的条数,假设马的位置是固定不动的,并不是卒走一步马走一步。
Input
一行四个数据,用空格分隔,分别表示B点的坐标和马的坐标。
Output
一个数据,表示所有的路径条数。
Sample Input
6 6 3 3
Sample Output
6
Hint
Source
代码实现:
这是我一开始做这道题时的代码:c语言代码,从书上看的基本上是照着打的,当时也不十分的理解
#include<stdio.h>
int main()
{
int dx[9]={0,-2,-1,1,2,2,1,-1,-2};
int dy[9]={0,1,2,2,1,-1,-2,-2,-1};
int m , n , x, y,i , j ;
long long int f[20][20]={0};
int g[20][20]={0};
scanf("%d %d %d %d",&n,&m,&x,&y);
g[x][y]=1;
for(i=1;i<=8;i++)
if(x+dx[i]>=0&&x+dx[i]<=n&&y+dy[i]>=0&&y+dy[i]<=m)
g[x+dx[i]][y+dy[i]]=1;
for(i=1;i<=n;i++)
{
if(g[i][0]!=1)
f[i][0]=1;
else
for(;i<=n;i++)
{
f[i][0]=0;
}
}
for(j=1;j<=m;j++)
{
if(g[0][j]!=1)
f[0][j]=1;
else
for(;j<=m;j++)
f[0][j]=0;
}
for(i=1;i<=n;i++)
{
for(j=1;j<=m;j++)
{
if(g[i][j]==1)
f[i][j]=0;
else
f[i][j]=f[i-1][j]+f[i][j-1];
}
}
printf("%lld\n",f[n][m]);
return 0;
}
/***************************************************
****************************************************/
下面是我后来再一次做这道题脱离了课本,自己理解着写出来的,当然是上面的代码给于的思想 代码如下:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{
int n , m , x , y ;
int ma[9][2] ={0,0,1,2,1,-2,-1,2,-1,-2,2,1,2,-1,-2,1,-2,-1} ;//马可以走的地方
int f[20][20] ; //用于记录路径
int g[20][20] ; // 用于判断马的位置
scanf("%d %d %d %d",&n,&m,&x,&y) ; //输入数据
//初始化
memset(f,0,sizeof(f)) ;
memset(g,0,sizeof(g)) ;
for(int i = 0 ; i<9 ; i++ )
{
int dx , dy ;
dx = x+ma[i][0] ;
dy = y + ma[i][1] ;
//防越界
if(dx<0||dx>n||dy<0||dy>m)
continue ;
else g[dx][dy] = 1 ; //马的控制点
}
//第一列初始化
for(int i=1 ; i <= n ; i++)
{
if(!g[i][0])
f[i][0] = 1 ;
else
break ;
}
//第一行初始化
for(int i = 1 ; i<= m ;i++)
{
if(!g[0][i])
f[0][i] =1 ;
else
break;
}
//动态规划求路径
for(int i=1 ; i<=n ; i++)
{
for(int j = 1 ;j<=m;j++)
//如果遇到马的控制点说明,此路不通,f[i][j]为0
if(g[i][j]==1)
f[i][j] = 0 ;
//经分析可知到达f[i][j]的路径等于从上面的路径和从右面的路径之和
else
f[i][j] = f[i-1][j] + f[i][j-1] ;
}
printf("%d\n",f[n][m]) ;
return 0 ;
}
/***************************************************
f[i][j]的取值如下:
0 1 1 1 1 1 1
1 2 0 1 0 1 2
1 0 0 1 1 0 2
1 1 1 0 1 1 3
1 0 1 1 2 0 3
1 1 0 1 0 0 3
1 2 2 3 3 3 6
f[i][j]的数值代表是到达该点的路径。
****************************************************/
现在对这道题的理解
现在学了DFS算法,决定用DFS算法再重新做一遍
代码如下:
#include<bits/stdc++.h>
using namespace std;
int mmp[100][100] ;//棋盘
int vis[100][100] ; //标记变量
int step = 0 ; //记录路径数
int a ,b ,n , m ;
int next1[9][2]={0,0,-2,1,2,1,-2,-1,2,-1,1,2,1,-2,-1,-2,-1,2}; //马的走动方式
void dfs(int x , int y)
{
int i ;
int next[2][2] = {{0,1},{1,0}} ; //卒的走动方式,卒无法向上走,也无法向右走
int tx ,ty ;
if(x==n&&y==m)
step++ ;
for(i=0;i<2;i++)
{
tx = x + next[i][1] ;
ty = y + next[i][0] ;
if(tx<0 || tx>n || ty < 0 || ty > m)
continue ;
if(!vis[tx][ty]&&mmp[tx][ty])
{
vis[tx][ty] = 1 ;
dfs(tx,ty) ;
vis[tx][ty] = 0 ;
}
}
}
int main()
{
int i ;
cin>>n>>m>>a>>b ; //a,b是马的坐标。
memset(vis,0,sizeof(vis)) ;
memset(mmp,1,sizeof(mmp)) ; //先假设棋盘上没有马
for(i=0;i<=8;i++)
{
if(a+next1[i][0]>=0&&a+next1[i][0]<=n&&b+next1[i][1]>=0&&b+next1[i][1]<=m)
{
mmp[a+next1[i][0]][b+next1[i][1]] = 0 ; //马的阻挡,卒无法通过。
}
}
vis[0][0] = 1 ;
dfs(0,0) ;
cout<<step<<endl ;
return 0 ;
}
/*************************************
**************************************/
c语言版如下:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int mmp[20][20] ;
int vis[20][20] ;
int step ;
int ma[9][2] ={0,0,1,2,1,-2,-1,2,-1,-2,2,1,2,-1,-2,1,-2,-1} ;
int n , m ;
int b , c ;
void dfs(int x , int y)
{
if(x ==n&&y==m)
step++ ;
int next[2][2] = {1,0,0,1} ;
int i ;
int dx , dy ;
for(i= 0 ; i<2 ;i++)
{
dx = x + next[i][1] ;
dy = y + next[i][0] ;
if(dx<0||dx>n||dy<0||dy>m)
continue ;
if(!vis[dx][dy]&&mmp[dx][dy]==0)
{
vis[dx][dy] = 1 ;
dfs(dx,dy) ;
vis[dx][dy] = 0 ;
}
}
}
int main()
{
int i ;
int dx , dy ;
scanf("%d %d %d %d",&n,&m,&b,&c) ;
memset(vis,0,sizeof(vis)) ;
memset(mmp,0,sizeof(mmp)) ;
for(i = 0 ; i<= 8 ; i++)
{
dx = b + ma[i][0] ;
dy = c + ma[i][1] ;
if(dx<0||dx>n||dy<0||dy>m)
continue ;
else
mmp[dx][dy] = 1 ;;
}
vis[0][0] = 1 ;
dfs(0,0) ;
printf("%d\n",step) ;
return 0 ;
}
/***************************************************
****************************************************/