P1002题解

发布时间 2023-11-24 22:48:17作者: Xu_dh

思路

\(dp_{i,j}\) 表示第 \(i\)\(j\) 列卒走到这里有多少种方式。

卒是可以向右和下走,所以到这个点只能从左或上来,不难得出转移公式:\(dp_{i,j} = dp_{i-1,j}+dp_{i,j-1}\)

如果马在这个点上或者说马能到这个点上,那么卒不能到这个点,也就是卒到这个点的方式为 \(0\)

如何判断马能不能到这个点呢?我们需要一个方向数组,马能走八个方向,依次枚举这八个点是不是当前点即可。

以上就是全部思路,但是还要注意一下几点:

  • \(dp_{0,0}\) 赋值为 \(1\),初始化。
  • 在转移过程中会数组越界,所以需要判断。
  • 转移时如果当前点是 \((0,0)\) 则不进行转移,因为这是初始点,已经有值了。

AC CODE

#include <bits/stdc++.h>
using namespace std;
#define int long long
int dp[25][25];
int dx[8]={-1,-2,-2,-1,1,2,2,1},dy[8]={-2,-1,1,2,2,1,-1,-2};
signed main(){
	int n,m,x,y;
	cin>>n>>m>>x>>y;
	dp[0][0]=1;//初始值
	bool ok=1;
	for(int i=0;i<=n;i++){
		for(int j=0;j<=m;j++){
			if(i==0&&j==0)continue;//不能是初始点
			ok=1;
			if(i==x&&j==y)ok=0;//这个点是不是马的位置
			for(int k=0;k<8;k++){//这个点有没有被马控制
				if(i==x+dx[k]&&j==y+dy[k]){ok=0;break;}
			}
			if(ok){//转移
				if(i-1<0){//判断越界
					dp[i][j]=dp[i][j-1];
				}
				else if(j-1<0){
					dp[i][j]=dp[i-1][j];
				}
				else{
					dp[i][j]=dp[i-1][j]+dp[i][j-1];	
				}
				
			}
		} 
	}
	cout<<dp[n][m]<<endl;
	return 0;
}