过河卒问题(动态规划问题)
(个人结题思路记录)
(cr洛谷 过河卒)
棋盘上 A 点有一个过河卒,需要走到目标 BB 点。卒行走的规则:可以向下、或者向右。同时在棋盘上 C 点有一个对方的马,该马所在的点和所有跳跃一步可达的点称为对方马的控制点。因此称之为“马拦过河卒”。
棋盘用坐标表示,A 点 (0, 0)(0,0)、B 点 (n, m)(n,m),同样马的位置坐标是需要给出的。
现在要求你计算出卒从 AA 点能够到达 BB 点的路径的条数,假设马的位置是固定不动的,并不是卒走一步马走一步。
输入格式
一行四个正整数,分别表示 BB 点坐标和马的坐标。
输出格式
一个整数,表示所有的路径条数。
输入输出样例
输入 #1
6 6 3 3
输出 #1
6
解题过程:一开始用的dfs,数据小的时候能解出来,但是大了会超时,基本思路就是最典型的dfs模型套用。下面是c++代码:
#include<iostream>
using namespace std;
int n,m,x,y;
long long cnt;
int map[24][24];
int dx[2]={1,0};
int dy[2]={0,1};
//基本超过输入的nm基本超过15,运算起来就会超时了
//而且得出的cnt非常大,要注意定义数据类型,int肯定是不够
int search(int xx,int yy)
{
//最基本的dfs搜索模型套用
for(int i=0;i<2;i++)
{
int bx=xx+dx[i];
int by=yy+dy[i];
if(map[bx][by]==0 && bx>=0 && bx<=n && by>=0 && by<=m)
{
map[bx][by]=1;
if(bx==n &&by==m) cnt++;
else search(bx,by);
map[bx][by]=0;//回溯
}
}
}
int main(){
cin>>n>>m>>x>>y;
map[x][y]=-1;
//标记马控制的点 ,这里写的有点麻烦了,可以定义数据用循环实现的
if(x+1>=0&&x+1<=n&&y-2>=0&&y-2<=m) map[x+1][y-2]=-1;
if(x+2>=0&&x+2<=n&&y-1>=0&&y-1<=m) map[x+2][y-1]=-1;
if(x+2>=0&&x+2<=n&&y+1>=0&&y+1<=m) map[x+2][y+1]=-1;
if(x+1>=0&&x+1<=n&&y+2>=0&&y+2<=m) map[x+1][y+2]=-1;
if(x-1>=0&&x-1<=n&&y+2>=0&&y+2<=m) map[x-1][y+2]=-1;
if(x-2>=0&&x-2<=n&&y+1>=0&&y+1<=m) map[x-2][y+1]=-1;
if(x-2>=0&&x-2<=n&&y-1>=0&&y-1<=m) map[x-2][y-1]=-1;
if(x-1>=0&&x-1<=n&&y-2>=0&&y-2<=m) map[x-1][y-2]=-1;
if(map[n][m]==-1) cnt=0;//如果b点在马控制的位置那么是无法到的
else search(0,0);
cout<<cnt;
return 0;
}
应用动态规划思想求解思路
基本上也是很基础的思路,首先考虑边界,然后就是状态转移方程。不难想出,想要到达i,j位置,有两条路径:从i-1,j,以及,i,j-1,所以可以得出如果我们用f[][]来记录到达i,j的路径数,那么f[i][j]=f[i-1][j]+f[i][j-1],但是应用之后会发现有问题,正确的状态转移方程应该是f[i][j]=max(f[i][j],f[i-1][j]+f[i][j-1]),为啥,测几组数据就想明白了。
#include<iostream>
#include<algorithm>
using namespace std;
int fx[9]={0,-2,-1,1,2,2,1,-1,-2};
int fy[9]={0,1,2,2,1,-1,-2,-2,-1};
//这是所有马能走到的位置
int s[30][30];//记录当前位置是不是马控制的点
long long f[30][30];//记录从0,0到大i,j的线路数,数值可能会很大,注意数据类型
int main(){
int n,m,x,y;
cin>>n>>m>>x>>y;
n+=2;m+=2;x+=2;y+=2;
//防止数组越界出错
f[2][2]=1;//初始化边界
s[x][y]=1;//马的位置
for(int i=1;i<=8;i++)
s[x+fx[i]][y+fy[i]]=1;//标注吗控制的点
for(int i=2;i<=n;i++)
for(int j=2;j<=m;j++)
{
if(s[i][j]) continue;
f[i][j]=max(f[i][j],f[i-1][j]+f[i][j-1]);
//状态转移方程, 注意
/*注意,这里如果直接f[i][j]=f[i-1][j]+f[i][j-1]是计算不出的*/
}
cout<<f[n][m];
}