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

#include <cstdio>
#include <cstdlib>
#include <cstring>

int mins(int a, int b) {
  if (a == -1)
    return b;
  if (b == -1)
    return a;
  else
    return (a > b) ? b : a;
}
int main(void) {
  int m, n;
  scanf("%d%d", &n, &m);
  while (n != 0) {

    int dkmp[150][10][77]; // 動計(メモ再)用。
    int maps[150][10][2];  // 盤面用。
    // memset(maps,-1,sizeof(maps));
    memset(dkmp, -1, sizeof(dkmp));
    memset(maps, -1, sizeof(maps));
    int i = 0;
    int j = 0;
    int xm;
    for (i = 0; i < n; i++) {
      scanf("%d", &xm);
      for (j = 0; j < xm; j++) {
        scanf("%d%d", &(maps[i][j][0]), &(maps[i][j][1]));
      }
    }
    // maps[i][j]には、岸からi+1つめの石で、j列にある石のあれ。
    // maps[n][x]は、向こう岸。だった。
    // maps[i][j][0]には、岸からi+1つめの石のある列。
    // maps[i][j][1]には、岸からi+1つめの石のあるすべ。
    for (j = 0; j < 10; j++) {
      if (maps[0][j][0] != -1) {
        dkmp[0][j][m] = 0;
      }
      if (maps[1][j][0] != -1 && m != 0) {
        dkmp[1][j][m - 1] = 0;
      }
    }
    int mema, memb, memc, memd, meme, memf;
    for (j = 0; j < 10; j++) {
      if (maps[1][j][0] == -1)
        break;
      mema = -1;
      memd = maps[1][j][0]; // 行
      meme = maps[1][j][1]; // 滑りやすさ
      for (i = 0; i < 10; i++) {
        if (dkmp[0][i][m] != -1) {
          memb = 0;             //=dkmp[0][p][m];累積
          memc = maps[0][i][0]; // 行
          memf = maps[0][i][1]; // 滑りやすさ
          mema = mins(mema, abs(memd - memc) * (meme + memf) + memb);
        } else
          break;
      }
      dkmp[1][j][m] = mema;
    }

    // ここから動計部
    // maps[i][j][m]には、i個目のj
    int k = 0, p = 0;
    for (i = 2; i < n; i++) {    // 岸からi個目の石
      for (j = 0; j < 10; j++) { // j番目の石
        if (maps[i][j][0] == -1)
          break;
        else {                       // 石がそこにあれば
          memd = maps[i][j][0];      // 行
          meme = maps[i][j][1];      // 滑りやすさ
          for (k = 0; k <= m; k++) { // 残りk回飛べるとき。
            mema = -1;
            for (p = 0; p < 10; p++) { // 石pから飛んできたとする。
              if (dkmp[i - 1][p][k] != -1) {
                memb = dkmp[i - 1][p][k]; // 累積
                memc = maps[i - 1][p][0]; // 行
                memf = maps[i - 1][p][1]; // 滑りやすさ
                mema = mins(mema, abs(memd - memc) * (meme + memf) + memb);
              } else
                break;
            }
            if (k < m) {
              for (p = 0; p < 10; p++) { // 石pから飛んできたとする。
                if (dkmp[i - 2][p][k + 1] != -1) {
                  memb = dkmp[i - 2][p][k + 1]; // 累積
                  memc = maps[i - 2][p][0];     // 行
                  memf = maps[i - 2][p][1];     // 滑りやす
                  mema = mins(mema, abs(memd - memc) * (meme + memf) + memb);
                } else
                  break;
              }
            }
            dkmp[i][j][k] = mema;
          }
        }
      }
    }

    // printf("%d\\x0020%d\\n",m,dkmp[n-1][0][0]);
    int ans = -1;
    for (i = 0; i < 10; i++) {
      if (maps[n - 1][i][0] == -1)
        break;
      for (j = 0; j <= m; j++) {
        ans = mins(ans, dkmp[n - 1][i][j]);
        // printf("%d\\n",dkmp[n-1][i][j]);
      }
    }
    for (i = 0; i < 10; i++) {
      if (maps[n - 2][i][0] == -1)
        break;
      for (j = 1; j <= m; j++) {
        ans = mins(ans, dkmp[n - 2][i][j]);
      }
    }

    printf("%d\\n", ans);
    scanf("%d%d", &n, &m);
  }
  return 0;
}

Error: MLE

Fixed submission:

#include <cstdio>
#include <cstdlib>
#include <cstring>

int dkmp[150][1000][76]; // 動計(メモ再)用。
int maps[150][1000];     // 盤面用。
int m, n;

int saiki(int tate, int yoko, int zan);

int mins(int a, int b) {
  if (a == -2)
    return b;
  else
    return (a > b) ? b : a;
}
int main(void) {

  scanf("%d%d", &n, &m);
  while (n != 0) {

    memset(maps, -1, sizeof(maps));
    memset(dkmp, -1, sizeof(dkmp));
    int i = 0;
    int j = 0;
    int jm, xm;
    for (i = 0; i < n; i++) {
      scanf("%d", &jm);
      for (j = 0; j < jm; j++) {
        scanf("%d", &xm);
        scanf("%d", &(maps[i][xm - 1]));
      }
    }
    // maps[i][j]には、岸からi+1つめの石で、j列にある石のあれ。
    // maps[n][x]は、向こう岸。
    int ans = -2;
    int memyo = 0;
    for (i = 0; i < 1000; i++) {
      if (maps[0][i] != -1) {
        memyo = saiki(0, i, m);
        ans = mins(ans, memyo);
      }
    }
    if (m > 0) {
      for (i = 0; i < 1000; i++) {
        if (maps[0][i] != -1) {
          memyo = saiki(1, i, m - 1);
          ans = mins(ans, memyo);
        }
      }
    }
    printf("%d\\n", ans);
    scanf("%d%d", &n, &m);
  }
  return 0;
}

// 再帰用。縦tate、横yokoの石で、残りzan回飛べるとき、
// 岸にたどり着くまでの危険度の最小値を返す。
// dkmpのが-1なら未調査。-2なら到達不可能。
int saiki(int tate, int yoko, int zan) {
  if (dkmp[tate][yoko][zan] != -1) {
    return dkmp[tate][yoko][zan];
  }

  if (tate + 1 >= n || (tate + 2 >= n && zan > 0)) {
    dkmp[tate][yoko][zan] = 0;
    return 0;
  }

  int ret = -2, si, mema = 0, memb = 0, memc = 0;
  for (si = 0; si < 1000; si++) {
    mema = maps[tate + 1][si];
    if (mema != -1) {
      memb = saiki(tate + 1, si, zan);
      if (memb == -2)
        continue;
      memc = (mema + maps[tate][yoko]) * (abs(yoko - si));
      ret = mins(ret, memb + memc);
    }
  }

  if (zan > 0) {
    for (si = 0; si < 1000; si++) {
      mema = maps[tate + 2][si];
      if (mema != -1) {
        memb = saiki(tate + 2, si, zan - 1);
        if (memb == -2)
          continue;
        memc = (mema + maps[tate][yoko]) * (abs(yoko - si));
        ret = mins(ret, memb + memc);
      }
    }
  }
  dkmp[tate][yoko][zan] = ret;
  return ret;
}