Problem p00471 (C++) — buggy submission, verdict: Memory Limit Exceeded

#include <bits/stdc++.h>

#define fst(t) std::get<0>(t)
#define snd(t) std::get<1>(t)
#define thd(t) std::get<2>(t)
#define unless(p) if (!(p))
#define until(p) while (!(p))

using ll = long long;
using P = std::tuple<int, int>;

const int dx[8] = {-1, 1, 0, 0, -1, -1, 1, 1},
          dy[8] = {0, 0, -1, 1, -1, 1, -1, 1};

int M, N, numHouse, gr, gc;
int map[12][12];
P neighbors[12][12][4];
int dp[1 << 24];

int rec(int r, int c, int n) {
  if (n == 0) {
    return r == gr || c == gc;
  }

  for (int i = 0; i < 4; ++i) {
    int rn, cn;
    std::tie(rn, cn) = neighbors[r][c][i];

    if (rn != -1) {
      neighbors[rn][cn][(i + 2) & 3] = neighbors[r][c][(i + 2) & 3];
    }
  }

  int res = 0;
  for (int i = 0; i < 4; ++i) {
    int rn, cn;
    std::tie(rn, cn) = neighbors[r][c][i];

    if (rn == -1) {
      continue;
    }

    res += rec(rn, cn, n - 1);
  }

  for (int i = 0; i < 4; ++i) {
    int rn, cn;
    std::tie(rn, cn) = neighbors[r][c][i];

    if (rn != -1) {
      neighbors[rn][cn][(i + 2) & 3] = std::make_tuple(r, c);
    }
  }

  return res;
}

int main() {
  std::cin.tie(nullptr);
  std::ios::sync_with_stdio(false);

  while (true) {
    std::cin >> M >> N;

    if (M == 0) {
      break;
    }

    numHouse = 0;
    std::fill(&neighbors[0][0][0], &neighbors[0][0][0] + 12 * 12 * 4,
              std::make_tuple(-1, -1));
    memset(dp, -1, sizeof(dp));

    for (int i = 0; i < N; ++i) {
      for (int j = 0; j < M; ++j) {
        std::cin >> map[i][j];

        if (map[i][j] == 1) {
          numHouse += 1;
        } else if (map[i][j] == 2) {
          gr = i;
          gc = j;
        }
      }
    }

    for (int i = 0; i < N; ++i) {
      for (int j = 0; j < M; ++j) {
        if (map[i][j] == 0) {
          continue;
        }

        for (int k = j - 1; k >= 0; --k) { // 左
          if (map[i][k] > 0) {
            neighbors[i][j][0] = std::make_tuple(i, k);
            break;
          }
        }

        for (int k = j + 1; k < M; ++k) { // 右
          if (map[i][k] > 0) {
            neighbors[i][j][2] = std::make_tuple(i, k);
            break;
          }
        }

        for (int k = i - 1; k >= 0; --k) { // 上
          if (map[k][j] > 0) {
            neighbors[i][j][1] = std::make_tuple(k, j);
            break;
          }
        }

        for (int k = i + 1; k < N; ++k) { // 下
          if (map[k][j] > 0) {
            neighbors[i][j][3] = std::make_tuple(k, j);
            break;
          }
        }
      }
    }

    int res = rec(gr, gc, numHouse);
    std::cout << res << std::endl;
  }
}


Error: MLE

Fixed submission:

#include <cstdio>
#include <cstring>
#include <unordered_map>

typedef std::pair<int, int> P;

template <class T> inline void hash_combine(std::size_t &seed, const T &v) {
  std::hash<T> hasher;
  seed ^= hasher(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
}

namespace std {
template <typename S, typename T> struct hash<pair<S, T>> {
  inline size_t operator()(const pair<S, T> &v) const {
    size_t seed = 0;
    ::hash_combine(seed, v.first);
    ::hash_combine(seed, v.second);
    return seed;
  }
};
} // namespace std

int M, N; // X, Y
int hashX[10][10], hashY[10][10];
int xs[24], ys[24], n;
std::unordered_map<P, int> dp;

bool can(int pos, int pos2, int state) {
  if (xs[pos] != xs[pos2] && ys[pos] != ys[pos2]) {
    return false;
  }

  if (xs[pos] == xs[pos2]) {
    if (ys[pos] > ys[pos2]) {
      std::swap(pos, pos2);
    }

    return (state & (hashY[ys[pos2] - 1][xs[pos]] ^ hashY[ys[pos]][xs[pos]])) ==
           0;
    // for(int i=0;i<n;i++){
    //     if(i == pos || i == pos2){continue;}
    //     if((state >> i & 1) &&
    //        xs[i] == xs[pos] &&
    //        ys[pos] < ys[i] && ys[i] < ys[pos2]){
    //         // printf("1: %d\\n", i);
    //         return false;
    //     }
    // }
  }

  if (xs[pos] > xs[pos2]) {
    std::swap(pos, pos2);
  }

  return (state & (hashX[ys[pos]][xs[pos2] - 1] ^ hashX[ys[pos]][xs[pos]])) ==
         0;
  // for(int i=0;i<n;i++){
  //     if(i == pos || i == pos2){continue;}
  //     if((state >> i & 1) &&
  //        ys[i] == ys[pos] &&
  //        xs[pos] < xs[i] && xs[i] < xs[pos2]){
  //         // printf("2: %d\\n", i);
  //         return false;
  //     }
  // }
}

int rec(int pos, int state) {
  P p = std::make_pair(pos, state);
  if (dp.count(p) > 0) {
    return dp[p];
  }

  int count = __builtin_popcount(state);
  if (count == n - 1) {
    return can(pos, 0, state);
  }

  int res = 0;
  for (int i = 1; i < n; i++) {
    if (!(state >> i & 1) && can(pos, i, state)) {
      // printf("%d -> %d\\n", pos, i);
      res += rec(i, state | (1 << i));
    }
  }
  // printf("ended...\\n");

  return dp[p] = res;
}

int main() {
  while (scanf("%d %d", &M, &N), M) {
    n = 1;
    for (int i = 0; i < N; i++) {
      for (int j = 0; j < M; j++) {
        int v;
        scanf("%d", &v);

        if (v == 1) {
          xs[n] = j;
          ys[n] = i;
          hashX[i][j] = 1 << n;
          hashY[i][j] = 1 << n++;
        } else if (v == 2) {
          xs[0] = j;
          ys[0] = i;
          hashX[i][j] = 1;
          hashY[i][j] = 1;
        }
      }
    }

    for (int i = 0; i < N; i++) {
      for (int j = 1; j < M; j++) {
        hashX[i][j] |= hashX[i][j - 1];
      }
    }

    for (int i = 0; i < M; i++) {
      for (int j = 1; j < N; j++) {
        hashY[j][i] |= hashY[j - 1][i];
      }
    }

    // for(int i=0;i<n;i++){printf("%d, %d\\n", xs[i], ys[i]);}

    // printf("%d\\n", can(0, 3, 1 << 5));
    // printf("%d\\n", hashY[1][2] ^ hashY[0][2]);
    printf("%d\\n", rec(0, 0));

    dp.clear();
    for (int i = 0; i < N; i++) {
      for (int j = 0; j < M; j++) {
        hashX[i][j] = 0;
        hashY[i][j] = 0;
      }
    }
  }
}