1314:【例3.6】过河卒(Noip2002)

【题目描述】
棋盘上A点有一个过河卒,需要走到目标B点。卒行走的规则:可以向下、或者向右。同时在棋盘上的某一点有一个对方的马(如C点),该马所在的点和所有跳跃一步可达的点称为对方马的控制点,如图3-1中的C点和P1,……,P8,卒不能通过对方马的控制点。棋盘用坐标表示,A点(0,0)、B点(n, m) (n,m为不超过20的整数),同样马的位置坐标是需要给出的,C≠A且C≠B。现在要求你计算出卒从A点能够到达B点的路径的条数。

【输入】
给出n、m和C点的坐标。

【输出】
从A点能够到达B点的路径的条数。

【输入样例】
8 6 0 4
【输出样例】
1617
这道题的阉割版我觉得是 移动路线那道题,大体思路差不多,这道题我一开始用的深搜
深搜版本

#include<iostream>
using namespace std;
const int maxn = 100+5;
int row,col,mx,my,ans=0;
bool pan(int x , int y){
	return x>=0 && y>=0 && x<=row && y<=col ;
	
}
bool chi(int x, int y){
	if( mx-1 == x && my+2 == y) return false;
	if( mx-2 == x && my+1 == y) return false;
	if( mx-2 == x && my-1 == y) return false;
	if( mx-1 == x && my-2 == y) return false;
	if( mx+1 == x && my-2 == y) return false;
	if( mx+2 == x && my-1 == y) return false;
	if( mx+2 == x && my+1 == y) return false;
	if( mx+1 == x && my+2 == y) return false;
	if( mx == x && my == y) return false; 
	return true;
}
void DFS(int x , int y){
	if(!pan(x,y)) return ;
	if(!chi(x,y) ) return ;
	if(x ==row && y == col){
		ans++;
		return ;
    }
	DFS(x+1,y);
	DFS(x,y+1);
}
int main(){
   cin>>row>>col>>mx>>my;
   DFS(0,0);
   cout<<ans ;
	return 0;
}

但是超时了,之过了2个测试点
那只能递推了,
递推与递归的区别
移动路线那个也可以用递推,递推的重点是找到关系,
简单的递推关系 f[i][j] = f[i-1][j] + f[i][j-1]就不细说了
重点是 马的处理,马的位置,以及马能走到的位置 都应该是 0,
还有边界的问题,想移动路线那道题,只要把边界都设置成1就可以了,这道题如果边界上有马的范围,那之后都应该是0,因为走不到,
递推

#include<iostream>
using namespace std;
int n,m,cx,cy;
long long bk[40][40],f[40][40];
int main(){
    cin>>n>>m>>cx>>cy;
     f[0][0] = 1;
     bk[cx][cy]=1;
     if(cx-1>=0&&cy-2>=0)bk[cx-1][cy-2]=1;
     if(cx+1<=n&&cy-2>=0)bk[cx+1][cy-2]=1;
     if(cx-2>=0&&cy-1>=0)bk[cx-2][cy-1]=1;
     if(cx+2<=n&&cy-1>=0)bk[cx+2][cy-1]=1;
     if(cx-2>=0&&cy+1<=m)bk[cx-2][cy+1]=1;
     if(cx+2<=n&&cy+1<=m)bk[cx+2][cy+1]=1;
     if(cx-1>=0&&cy+2<=m)bk[cx-1][cy+2]=1;
     if(cx+1<=n&&cy+2<=m)bk[cx+1][cy+2]=1;
      for(int i = 1 ;i <=n;i++) 
      	if(!bk[i][0]) f[i][0] = f[i-1][0];
      for(int i = 1 ;i <=m;i++)
       if(!bk[0][i]) f[0][i] = f[0][i-1];
       for(int i = 1 ; i<=n;i++){
       	for(int j= 1;j<=m;j++){
       		if(!bk[i][j]) f[i][j] = f[i-1][j] + f[i][j-1];
       		else f[i][j] = 0;
		   }
	   }
      
      
      
    cout<<f[n][m];
	return 0;
}

感觉深搜的做法好想,但是容易超时,递推的边界处理稍微麻烦一点,递推和递归的区别和有点也要弄清楚
参考

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值