[debug][pieces] 洛谷P1002 过河卒——递归、动规复习

递归自顶向下,动规自底向上。
递归对应搜索,动规对应递推。

递归必须要记忆化搜索,否则会T,由于使用尾递归,在这个情形下和动规效率相差无几。个人更喜欢递归,因为清晰简洁(=______=)

#include 
bool tac[22][22];
int m, n, hx, hy, 
   dx[8] = {2, 1, -1, -2, -2, -1, 1, 2},
   dy[8] = {1, 2, 2, 1, -1, -2, -2, -1};
long long mem[21][21];

using namespace std;
inline bool legal(int x, int y)
{
   return x >= 0 && x <= n && y >= 0 && y <= m;
}

void init()
{
   int i;
   cin >> n >> m >> hx >> hy;
   for (i = 0; i <= m+1; i++)
      tac[n+1][i] = true;
   for (i = 0; i <= n; i++)
      tac[i][m+1] = true;
   for (i = 0; i < 8; i++)
      if (legal(hx+dx[i], hy+dy[i]))
         tac[hx+dx[i]][hy+dy[i]] = true;
   tac[hx][hy] = true;
   // for (int i = 0; i <= n+1; i++)
   // {
   //    for (int j = 0; j <= m+1; j++)
   //       cout << tac[i][j];
   //    cout << endl;
   // }
}

long long sln(int x, int y)
{
   if (tac[x][y])
      return 0;
   if (x == n && y == m)
      return 1;
   if (mem[x][y])
      return mem[x][y];
   return mem[x][y] = sln(x+1, y) + sln(x, y+1);
}

int main()
{
   init();
   cout << sln(0, 0);
}

动规第一种方法是填表(略)。
动规第二种方法,把递推数组滚动起来。这里不简单地使用两个数组滚动。

如果要滚动两个维度的数组,转移方程为:
dp[i&1][j] = dp[(i-1)&1][j]+dp[i&1][j-1]
dp[i%2][j] = dp[(i-1)%2][j]+dp[i%2][j-1](不建议,因为机器算除法效率低)

我们可以直接滚动一维来实现(来自Loner_Knowledge的题解):[debug][pieces] 洛谷P1002 过河卒——递归、动规复习_第1张图片

#include 
bool tac[22][22];
int m, n, hx, hy,
    dx[8] = {2, 1, -1, -2, -2, -1, 1, 2},
    dy[8] = {1, 2, 2, 1, -1, -2, -2, -1};

long long dp[22];

using namespace std;
inline bool legal(int x, int y)
{
   return x >= 0 && x <= n && y >= 0 && y <= m;
}

void init()
{
   int i;
   cin >> n >> m >> hx >> hy;
   for (i = 0; i <= m + 1; i++)
      tac[n + 1][i] = true;
   for (i = 0; i <= n; i++)
      tac[i][m + 1] = true;
   for (i = 0; i < 8; i++)
      if (legal(hx + dx[i], hy + dy[i]))
         tac[hx + dx[i]][hy + dy[i]] = true;
   tac[hx][hy] = true;
   dp[0] = 1;
}

int main()
{
   init();
   for (int i = 0, j; i <= n; ++i)
      for (dp[0] *=!tac[i][0], j = 1; j <= m; ++j)
         (dp[j] += dp[j - 1]) *= !tac[i][j];
   cout << dp[m];
   return 0;
}

你可能感兴趣的:(C/C++,#,动态规划/dp,算法,动态规划)