题目描述
棋盘上AA点有一个过河卒,需要走到目标BB点。卒行走的规则:可以向下、或者向右。同时在棋盘上CC点有一个对方的马,该马所在的点和所有跳跃一步可达的点称为对方马的控制点。因此称之为“马拦过河卒”。
棋盘用坐标表示,AA点(0, 0)(0,0)、BB点(n, m)(n,m)(nn, mm为不超过2020的整数),同样马的位置坐标是需要给出的。
现在要求你计算出卒从AA点能够到达BB点的路径的条数,假设马的位置是固定不动的,并不是卒走一步马走一步。
输入格式
一行四个数据,分别表示BB点坐标和马的坐标。
输出格式
一个数据,表示所有的路径条数。
输入输出样例
输入 #1
6 6 3 3
输出 #1
6
说明/提示
结果可能很大!
思路:由题意卒可以向下或向右走,可以很明确的分辨出两个状态。由此可以判断出可以使用DP来解决问题。
我们可以设f[i][j]表示从(0,0)到达(i,j)的路径的数目。f[i][j]的属性为数字的和。
我们将f[i][j]看作是一个集合,那么它可以划分成那些不同的集合呢,明显可以划分成f[i-1][j]和f[i][j-1]。
因此得出状态转移方程 f[i][j] = f[i-1][j] + f[i][j-1] ;
由于涉及到 i-1 ,j-1等,要把整个矩阵右移,所以下标加1。
并且由于我们遍历是要从(1,1)开始,如果用上述方程那么f[1][1]将会由1变为0。
所以我们用 方程
f[i][j]=max(f[i-1][j]+f[i][j-1],f[i][j]);来表示。这两个方程本质没区别,只针对(1,1)这个点,其余的点f[i-1][j]+f[i][j-1]一定比f[i][j]大
#include <iostream> using namespace std; long long f[50][50]; bool v[50][50]; int main() { int x1,y1,x2,y2; cin >> x1 >> y1 >> x2 >> y2; x1++,y1++,x2++,y2++; f[1][1]=1; v[x2][y2]=1; if(x2-2>=1&&x2-2<=50&&y2-1>=1&&y2-1<=50) v[x2-2][y2-1]=1; if(x2-2>=1&&x2-2<=50&&y2+1>=1&&y2+1<=50) v[x2-2][y2+1]=1; if(x2-1>=1&&x2-1<=50&&y2-2>=1&&y2-2<=50) v[x2-1][y2-2]=1; if(x2-1>=1&&x2-1<=50&&y2+2>=1&&y2+2<=50) v[x2-1][y2+2]=1; if(x2+2>=1&&x2+2<=50&&y2-1>=1&&y2-1<=50) v[x2+2][y2-1]=1; if(x2+2>=1&&x2+2<=50&&y2+1>=1&&y2+1<=50) v[x2+2][y2+1]=1; if(x2+1>=1&&x2+1<=50&&y2-2>=1&&y2-2<=50) v[x2+1][y2-2]=1; if(x2+1>=1&&x2+1<=50&&y2+2>=1&&y2+2<=50) v[x2+1][y2+2]=1; for(int i=1;i<=x1;i++) { for(int j=1;j<=y1;j++) { if(!v[i][j]) { f[i][j]=max(f[i-1][j]+f[i][j-1],f[i][j]); } } } cout << f[x1][y1] << endl; return 0; }