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

#include <algorithm>
#include <cassert>
#include <cstdlib>
#include <fstream>
#include <iostream>
#include <list>
#include <map>
#include <math.h>
#include <queue>
#include <random>
#include <set>
#include <stack>
#include <stdio.h>
#include <string>
#include <time.h>
#include <tuple>
#include <unordered_map>
#include <vector>
using namespace std;
#define LL long long
#define MP(a, b) make_pair(a, b)
#define MMP(a, b, c) make_pair(make_pair(a, b), c)
#define MAX 1000000000
#undef INT_MIN
#undef INT_MAX
#define INT_MIN -2147483648
#define INT_MAX 2147483647
#define LL_MIN -9223372036854775808
#define LL_MAX 9223372036854775807
#define PI 3.14159265359

vector<pair<int, int>> house;
vector<pair<int, int>> way[23];
int ok[23];

int solve(int i, int j) {
  if (i == (1 << house.size()) - 1)
    return ok[j];
  int ans = 0;
  if ((i & (1 << j)) == 0)
    return 0;
  bool flg = true;
  for (int k = way[j].size() - 1; k >= 0; k--) {
    if (way[j][k] == MP(-1, -1)) {
      flg = true;
      continue;
    }
    if (flg == false)
      continue;
    if ((i & way[j][k].second) == way[j][k].second &&
        (i & (1 << way[j][k].first)) == 0) {
      ans += solve(i + (1 << way[j][k].first), way[j][k].first);
      flg = false;
    }
  }
  return ans;
}

int main() {
  iostream::sync_with_stdio(false);

START:

  int m, n;
  cin >> m >> n;
  if (n == 0 && m == 0)
    return 0;
  int a[10][10];
  house.clear();
  pair<int, int> kyokai;
  for (int i = 0; i < n; i++) {
    for (int j = 0; j < m; j++) {
      cin >> a[i][j];
      if (a[i][j] == 0)
        a[i][j] = -1; // 空地
      else if (a[i][j] == 2) {
        a[i][j] = -2; // 教会
        kyokai = MP(i, j);
      } else {
        a[i][j] = house.size();
        house.push_back(MP(i, j));
      }
    }
  }

  // 経路計算
  for (int i = 0; i < house.size(); i++) {
    way[i].clear();
    int x = house[i].first;
    int y = house[i].second;
    int tmp = 0;
    for (int j = x + 1; j < n; j++) {
      if (a[j][y] >= 0) {
        way[i].push_back(MP(a[j][y], tmp));
        tmp += 1 << a[j][y];
      }
    }
    way[i].push_back(MP(-1, -1));
    tmp = 0;
    for (int j = x - 1; j >= 0; j--) {
      if (a[j][y] >= 0) {
        way[i].push_back(MP(a[j][y], tmp));
        tmp += 1 << a[j][y];
      }
    }
    way[i].push_back(MP(-1, -1));
    tmp = 0;
    for (int j = y + 1; j < m; j++) {
      if (a[x][j] >= 0) {
        way[i].push_back(MP(a[x][j], tmp));
        tmp += 1 << a[x][j];
      }
    }
    way[i].push_back(MP(-1, -1));
    tmp = 0;
    for (int j = y - 1; j >= 0; j--) {
      if (a[x][j] >= 0) {
        way[i].push_back(MP(a[x][j], tmp));
        tmp += 1 << a[x][j];
      }
    }
  }

  // 教会隣接家dp初期化
  for (int i = 0; i < house.size(); i++) {
    ok[i] = 0;
  }
  for (int i = kyokai.first + 1; i < n; i++) {
    if (a[i][kyokai.second] >= 0) {
      ok[a[i][kyokai.second]] = 1;
    }
  }
  for (int i = kyokai.first - 1; i >= 0; i--) {
    if (a[i][kyokai.second] >= 0) {
      ok[a[i][kyokai.second]] = 1;
    }
  }
  for (int i = kyokai.second + 1; i < m; i++) {
    if (a[kyokai.first][i] >= 0) {
      ok[a[kyokai.first][i]] = 1;
    }
  }
  for (int i = kyokai.second - 1; i >= 0; i--) {
    if (a[kyokai.first][i] >= 0) {
      ok[a[kyokai.first][i]] = 1;
    }
  }

  // 最終的な答え
  int ans = 0;
  for (int i = kyokai.first + 1; i < n; i++) {
    if (a[i][kyokai.second] >= 0) {
      ans += solve(1 << a[i][kyokai.second], a[i][kyokai.second]);
      break;
    }
  }
  for (int i = kyokai.first - 1; i >= 0; i--) {
    if (a[i][kyokai.second] >= 0) {
      ans += solve(1 << a[i][kyokai.second], a[i][kyokai.second]);
      break;
    }
  }
  for (int i = kyokai.second + 1; i < m; i++) {
    if (a[kyokai.first][i] >= 0) {
      ans += solve(1 << a[kyokai.first][i], a[kyokai.first][i]);
      break;
    }
  }
  for (int i = kyokai.second - 1; i >= 0; i--) {
    if (a[kyokai.first][i] >= 0) {
      ans += solve(1 << a[kyokai.first][i], a[kyokai.first][i]);
      break;
    }
  }
  cout << ans << endl;

  goto START;

  return 0;
}


Error: MLE

Fixed submission:

#include <algorithm>
#include <cassert>
#include <cstdlib>
#include <fstream>
#include <iostream>
#include <list>
#include <map>
#include <math.h>
#include <queue>
#include <random>
#include <set>
#include <stack>
#include <stdio.h>
#include <string>
#include <time.h>
#include <tuple>
#include <unordered_map>
#include <vector>
using namespace std;
#define LL long long
#define MP(a, b) make_pair(a, b)
#define MMP(a, b, c) make_pair(make_pair(a, b), c)
#define MAX 1000000000
#undef INT_MIN
#undef INT_MAX
#define INT_MIN -2147483648
#define INT_MAX 2147483647
#define LL_MIN -9223372036854775808
#define LL_MAX 9223372036854775807
#define PI 3.14159265359

int dp[1 << 23][23]; // ここまで、現在地
bool already[1 << 23][23] = {};
vector<pair<int, int>> house;
vector<pair<int, int>> way[23];

int solve(int i, int j) {
  if (already[i][j])
    return dp[i][j];
  int ans = 0;
  if ((i & (1 << j)) == 0)
    return 0;
  bool flg = true;
  for (int k = way[j].size() - 1; k >= 0; k--) {
    if (way[j][k] == MP(-1, -1)) {
      flg = true;
      continue;
    }
    if (flg == false)
      continue;
    if ((i & way[j][k].second) == way[j][k].second &&
        (i & (1 << way[j][k].first)) == 0) {
      ans += solve(i + (1 << way[j][k].first), way[j][k].first);
      flg = false;
    }
  }
  // already[i][j] = true;
  // dp[i][j] = ans;
  return ans;
}

int main() {
  iostream::sync_with_stdio(false);

START:

  int m, n;
  cin >> m >> n;
  if (n == 0 && m == 0)
    return 0;
  int a[10][10];
  house.clear();
  pair<int, int> kyokai;
  for (int i = 0; i < n; i++) {
    for (int j = 0; j < m; j++) {
      cin >> a[i][j];
      if (a[i][j] == 0)
        a[i][j] = -1; // 空地
      else if (a[i][j] == 2) {
        a[i][j] = -2; // 教会
        kyokai = MP(i, j);
      } else {
        a[i][j] = house.size();
        house.push_back(MP(i, j));
      }
    }
  }

  // 経路計算
  for (int i = 0; i < house.size(); i++) {
    way[i].clear();
    int x = house[i].first;
    int y = house[i].second;
    int tmp = 0;
    for (int j = x + 1; j < n; j++) {
      if (a[j][y] >= 0) {
        way[i].push_back(MP(a[j][y], tmp));
        tmp += 1 << a[j][y];
      }
    }
    way[i].push_back(MP(-1, -1));
    tmp = 0;
    for (int j = x - 1; j >= 0; j--) {
      if (a[j][y] >= 0) {
        way[i].push_back(MP(a[j][y], tmp));
        tmp += 1 << a[j][y];
      }
    }
    way[i].push_back(MP(-1, -1));
    tmp = 0;
    for (int j = y + 1; j < m; j++) {
      if (a[x][j] >= 0) {
        way[i].push_back(MP(a[x][j], tmp));
        tmp += 1 << a[x][j];
      }
    }
    way[i].push_back(MP(-1, -1));
    tmp = 0;
    for (int j = y - 1; j >= 0; j--) {
      if (a[x][j] >= 0) {
        way[i].push_back(MP(a[x][j], tmp));
        tmp += 1 << a[x][j];
      }
    }
  }

  // 教会隣接家dp初期化
  for (int i = 0; i < house.size(); i++) {
    dp[(1 << house.size()) - 1][i] = 0;
    already[(1 << house.size()) - 1][i] = true;
  }
  for (int i = kyokai.first + 1; i < n; i++) {
    if (a[i][kyokai.second] >= 0) {
      dp[(1 << house.size()) - 1][a[i][kyokai.second]] = 1;
    }
  }
  for (int i = kyokai.first - 1; i >= 0; i--) {
    if (a[i][kyokai.second] >= 0) {
      dp[(1 << house.size()) - 1][a[i][kyokai.second]] = 1;
    }
  }
  for (int i = kyokai.second + 1; i < m; i++) {
    if (a[kyokai.first][i] >= 0) {
      dp[(1 << house.size()) - 1][a[kyokai.first][i]] = 1;
    }
  }
  for (int i = kyokai.second - 1; i >= 0; i--) {
    if (a[kyokai.first][i] >= 0) {
      dp[(1 << house.size()) - 1][a[kyokai.first][i]] = 1;
    }
  }

  for (int i = (1 << house.size()) - 2; i >= 0; i--) {
    for (int j = 0; j < house.size(); j++) {
      already[i][j] = false;
    }
  }

  /*
  //dp
  for(int i=(1<<house.size())-2; i>=0; i--){ //2^23
          for(int j=0; j<house.size(); j++){ //23
                  dp[i][j] = 0;
                  if((i&(1<<j)) == 0) continue;
                  for(int k=0; k<way[j].size(); k++){ //20
                          if((i&way[j][k].second) == 0 &&
  (i&(1<<way[j][k].first)) == 0){ dp[i][j] +=
  dp[i+(1<<way[j][k].first)][way[j][k].first];
                          }
                  }
          }
  }
  */

  // 最終的な答え
  int ans = 0;
  for (int i = kyokai.first + 1; i < n; i++) {
    if (a[i][kyokai.second] >= 0) {
      ans += solve(1 << a[i][kyokai.second], a[i][kyokai.second]);
      break;
    }
  }
  for (int i = kyokai.first - 1; i >= 0; i--) {
    if (a[i][kyokai.second] >= 0) {
      ans += solve(1 << a[i][kyokai.second], a[i][kyokai.second]);
      break;
    }
  }
  for (int i = kyokai.second + 1; i < m; i++) {
    if (a[kyokai.first][i] >= 0) {
      ans += solve(1 << a[kyokai.first][i], a[kyokai.first][i]);
      break;
    }
  }
  for (int i = kyokai.second - 1; i >= 0; i--) {
    if (a[kyokai.first][i] >= 0) {
      ans += solve(1 << a[kyokai.first][i], a[kyokai.first][i]);
      break;
    }
  }
  cout << ans << endl;

  goto START;

  /*
  //デバッグ
  for(int i=0; i<house.size(); i++){
          for(int j=0; j<way[i].size(); j++){
                  cout << way[i][j].first << " ";
          }
          cout << endl;
  }

  for(int i=0; i<(1<<house.size()); i++){
          for(int j=0; j<house.size(); j++){
                  cout << dp[i][j] << " ";
          }
          cout << endl;
  }
  */

  return 0;
}