【洛谷P1002】——过河卒dp问题
在解动态规划问题时,许多人认为找到状态转移方程是最难的,我也认同这一观点。一道动态规划题能找到状态转移方程就完成了一半。
然而另一半在我看来有时候比找状态转移方程更恶心——dp数组的初始化以及越界问题。
想要克服以上两个问题都需要大量的练习。任重而道远。
题目描述:
#include<iostream>
#include<vector>
using namespace std;
int main() {
vector<int> dirX{ -1,-2,-2,-1,1,2,2,1 };
vector<int> dirY{ 2,1,-1,-2,-2,-1,1,2 };
int bx, by, mx, my;
cin >> bx >> by >> mx >> my;
vector<vector<long long>> dp(bx + 1, vector<long long>(by + 1,0));
vector<vector<bool>> flag(bx + 1, vector<bool>(by + 1, false));
for (int i = 0; i < 8; i++)
if(mx+dirX[i]>=0&&my+dirY[i]>=0&&mx+dirX[i]<bx+1&&my+dirY[i]<by+1)
flag[mx + dirX[i]][my + dirY[i]] = true;
flag[mx][my] = true;
dp[0][0] = 1;
for(int i=0;i<=bx;i++)
for (int j = 0; j <= by; j++) {
if (flag[i][j])
continue;
if (i)
dp[i][j] += dp[i - 1][j];
if (j)
dp[i][j] += dp[i][j - 1];
}
cout << dp[bx][by];
return 0;
}
关键点:题目中起点的坐标是(0,0),我们可以直接将它作为起点,也可以横纵坐标都加上1作为起点。这两种情况下一定要注意数组越界问题和状态转移方程的编程语言的呈现。题目中的状态转移方程为dp[i][j]=dp[i-1][j]+dp[i][j-1].可见如果我们直接将状态转移方程直接敲到代码中去,当i=0或j=0时会发生越界。因此我们要将这两种情况区分出来。由题意可知当i=0时,如果flag[i][j]=0,那么dp[i][j]=dp[i][j-1],同理当j=0,flag[i][j]=0时,dp[i][j]=dp[i-1][j]。当i>0&&j>0时,dp[i][j]=dp[i-1][j]+dp[i][j-1]。因此我们便可将其写为上述代码中第二个for循环中的样子。