【题目链接】
ybt 1314:【例3.6】过河卒(Noip2002)
ybt 1921:【02NOIP普及组】过河卒
洛谷 P1002 [NOIP2002 普及组] 过河卒
【题目考点】
1. 坐标型动态规划
【解题思路】
设状态数组dp,dp[i][j]表示从(0,0)到(i,j)的路径条数。
考虑卒到(i,j)位置的前一个位置可能是哪里,把可能的到(i,j)的前一个位置的路径数量加和,即为到(i,j)的路径数量。
- 如果(i,j)是(0,0),到起始位置的路径数量为1,所以:
dp[0][0]=1;
- 如果这个位置是马的控制点,那么到这里的路径数量为0。
- 除了上述情况,如果是在第0行,即i为0,那么到(i,j)的前一个位置只能是(i,j-1)。所以如果i为0:
dp[i][j] = dp[i][j-1];
- 除了上述情况,如果是在第0列,即j为0,那么到(i,j)的前一个位置只能是(i-1,j)。所以如果j为0:
dp[i][j] = dp[i-1][j];
- 除了上述情况,到(i,j)的前一个位置只能是它上面的位置(i-1,j)和左边的位置(i,j-1),所以:
dp[i][j] = dp[i-1][j]+dp[i][j-1];
先将dp数组初始化为-1,把马的控制点位置的值设为0。(0,0)位置设为1,而后遍历二维数组dp,按照上述递推关系做递推。最后输出dp[n][m]
。
【注意】:最终结果超出了int可以表示的范围,dp数组必须设为long long类型。
【题解代码】
解法1:递推 用dp的值判断一个位置是否被马控制
dp[i][j]为0表示该位置被马控制,为-1表示该位置尚未赋值。
#include <bits/stdc++.h>
using namespace std;
int dir[8][2]={{-1,2},{-1,-2},{1,2},{1,-2},{-2,1},{-2,-1},{2,1},{2,-1}};//方向数组:马走日下一步到的位置和当前位置的坐标差值
int main()
{
long long dp[25][25];//dp[i][j]:表示从(0,0)到(i,j)的路径条数。
memset(dp, -1, sizeof(dp));
int n, m, cx, cy;
cin >> n >> m >> cx >> cy;
dp[cx][cy] = 0;//设置马的控制点,值为0
for(int i = 0; i < 8; ++i)
{
int x = cx + dir[i][0], y = cy + dir[i][1];
if(x >= 0 && x <= n && y >= 0 && y <= m)
dp[x][y] = 0;
}
dp[0][0] = 1;
for(int i = 0; i <= n; ++i)
for(int j = 0; j <= m; ++j)
{
if(dp[i][j] == 0)//马控制的点不做计算
continue;
if(i == 0 && j == 0)
dp[i][j] = 1;
else if(i == 0)
dp[i][j] = dp[i][j-1];
else if(j == 0)
dp[i][j] = dp[i-1][j];
else
dp[i][j] = dp[i-1][j] + dp[i][j-1];
}
cout << dp[n][m];
return 0;
}
解法2:递推 设vis数字表示某位置是否被马控制
vis[i][j]为真表示该位置被马控制
#include <bits/stdc++.h>
using namespace std;
int dir[8][2]={{-1,2},{-1,-2},{1,2},{1,-2},{-2,1},{-2,-1},{2,1},{2,-1}};//方向数组:马走日下一步到的位置和当前位置的坐标差值
long long dp[25][25];//dp[i][j]:表示从(0,0)到(i,j)的路径条数。初值为0。
bool vis[25][25];//vis[i][j]:表示(i,j)位置是否被马控制
int main()
{
int n, m, cx, cy;
cin >> n >> m >> cx >> cy;
vis[cx][cy] = true;//设置马的控制点
for(int i = 0; i < 8; ++i)
{
int x = cx + dir[i][0], y = cy + dir[i][1];
if(x >= 0 && x <= n && y >= 0 && y <= m)
vis[x][y] = true;
}
dp[0][0] = 1;
for(int i = 0; i <= n; ++i)
for(int j = 0; j <= m; ++j)
{
if(vis[i][j])//马控制的点不做计算
continue;
if(i == 0 && j == 0)
dp[i][j] = 1;
else if(i == 0)
dp[i][j] = dp[i][j-1];
else if(j == 0)
dp[i][j] = dp[i-1][j];
else
dp[i][j] = dp[i-1][j] + dp[i][j-1];
}
cout << dp[n][m];
return 0;
}