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

#include <algorithm>
#include <cstdio>
#include <map>
#include <string>
#include <vector>

#define rep(i, n) for (int i = 0; i < (n); i++)

using namespace std;

const int INF = ((1 << 31) - 1) / 4;

struct train {
  int u, v, t1, t2, cost;
};
bool cmp0(const train &T1, const train &T2) {
  return T1.t1 < T2.t1 || T1.t1 == T2.t1 && T1.t2 < T2.t2;
} // (t1,t2) の昇順
bool cmp1(const train &T1, const train &T2) {
  return T1.t2 > T2.t2 || T1.t2 == T2.t2 && T1.t1 > T2.t1;
} // (t2,t1) の降順

int decode(const char *t) {
  int hh = (t[0] - '0') * 10 + (t[1] - '0');
  int mm = (t[3] - '0') * 10 + (t[4] - '0');
  return 60 * hh + mm - 8 * 60;
}

void calc_time(int n, int m, train *T, int dp[2][601][2001], int s) {
  rep(i, 2) rep(t, 601) rep(u, n) dp[i][t][u] = INF;

  sort(T, T + m, cmp0);
  dp[0][0][s] = 0;
  int iter = 0;
  rep(t, 601) {
    if (t < 600) { // 動かずに一分過ごす
      rep(u, n) dp[0][t + 1][u] = min(dp[0][t + 1][u], dp[0][t][u]);
    }
    while (iter < m && T[iter].t1 == t) { // 電車に乗る
      dp[0][T[iter].t2][T[iter].v] =
          min(dp[0][T[iter].t2][T[iter].v], dp[0][t][T[iter].u] + T[iter].cost);
      iter++;
    }
  }

  sort(T, T + m, cmp1);
  dp[1][600][s] = 0;
  iter = 0;
  for (int t = 600; t >= 0; t--) {
    if (t > 0) {
      rep(u, n) dp[1][t - 1][u] = min(dp[1][t - 1][u], dp[1][t][u]);
    }
    while (iter < m && T[iter].t2 == t) {
      dp[1][T[iter].t1][T[iter].u] =
          min(dp[1][T[iter].t1][T[iter].u], dp[1][t][T[iter].v] + T[iter].cost);
      iter++;
    }
  }
}

int main() {
  for (int m; scanf("%d", &m), m;) {
    int n = 0;
    map<string, int> f;
    f["Hakodate"] = n++;
    f["Tokyo"] = n++;

    train T[2000];
    rep(i, m) {
      char s1[32], t1[8], s2[32], t2[8];
      int cost;
      scanf("%s%s%s%s%d", s1, t1, s2, t2, &cost);
      if (f.count(s1) == 0)
        f[s1] = n++;
      if (f.count(s2) == 0)
        f[s2] = n++;
      int tt1 = decode(t1), tt2 = decode(t2);
      if (0 <= tt1 && tt2 <= 600) {
        T[i] = (train){f[s1], f[s2], tt1, tt2, cost};
      } else {
        i--;
        m--;
      }
    }

    // 頂点が多すぎて MLE するので,
    // 函館と東京の両方からたどり着ける頂点だけに制限する
    vector<int> G[4000];
    rep(i, m) G[T[i].u].push_back(T[i].v);
    bool vis[2][4000] = {};
    rep(i, 2) {
      vis[i][i] = true;
      int Q[4000], head = 0, tail = 0;
      Q[tail++] = i;
      while (head < tail) {
        int u = Q[head++];
        rep(j, G[u].size()) {
          int v = G[u][j];
          if (!vis[i][v])
            vis[i][v] = true, Q[tail++] = v;
        }
      }
    }
    bool kill[4000] = {};
    vector<int> V;
    rep(u, n) {
      if (!vis[0][u] || !vis[1][u])
        kill[u] = true;
      else
        V.push_back(u);
    }
    rep(i, m) {
      if (kill[T[i].u] || kill[T[i].v]) {
        swap(T[i], T[m - 1]);
        i--;
        m--;
      } else {
        T[i].u = lower_bound(V.begin(), V.end(), T[i].u) - V.begin();
        T[i].v = lower_bound(V.begin(), V.end(), T[i].v) - V.begin();
      }
    }

    // dp1[0][t][u] := ( 8:00 に函館にいて, 時刻 t に駅 u にいるときの最小コスト
    // ) dp1[1][t][u] := ( 18:00 に函館に戻れて, 時刻 t に駅 u
    // にいるときの最小コスト ) dp2 は dp1 の函館を東京に変えただけ.
    static int dp1[2][601][2001], dp2[2][601][2001];
    calc_time(n, m, T, dp1, 0);
    calc_time(n, m, T, dp2, 1);

    int ans = INF;
    rep(u, n) rep(t, 600 - 30 + 1) {
      ans = min(ans, dp1[0][t][u] + dp1[1][t + 30][u] + dp2[0][t][u] +
                         dp2[1][t + 30][u]);
    }
    printf("%d\\n", ans < INF ? ans : 0);
  }

  return 0;
}

Error: MLE

Fixed submission:

#include <algorithm>
#include <cstdio>
#include <map>
#include <string>

#define rep(i, n) for (int i = 0; i < (n); i++)

using namespace std;

const int INF = ((1 << 31) - 1) / 4;

struct train {
  int u, v, t1, t2, cost;
};
bool cmp0(const train &T1, const train &T2) {
  return T1.t1 < T2.t1 || T1.t1 == T2.t1 && T1.t2 < T2.t2;
} // (t1,t2) の昇順
bool cmp1(const train &T1, const train &T2) {
  return T1.t2 > T2.t2 || T1.t2 == T2.t2 && T1.t1 > T2.t1;
} // (t2,t1) の降順

int decode(const char *t) {
  int hh = (t[0] - '0') * 10 + (t[1] - '0');
  int mm = (t[3] - '0') * 10 + (t[4] - '0');
  return 60 * hh + mm - 8 * 60;
}

void calc_time(int n, int m, train *T, int dp[2][601][4000], int s) {
  rep(i, 2) rep(t, 601) rep(u, n) dp[i][t][u] = INF;

  sort(T, T + m, cmp0);
  dp[0][0][s] = 0;
  int iter = 0;
  rep(t, 601) {
    if (t < 600) { // 動かずに一分過ごす
      rep(u, n) dp[0][t + 1][u] = min(dp[0][t + 1][u], dp[0][t][u]);
    }
    while (iter < m && T[iter].t1 == t) { // 電車に乗る
      dp[0][T[iter].t2][T[iter].v] =
          min(dp[0][T[iter].t2][T[iter].v], dp[0][t][T[iter].u] + T[iter].cost);
      iter++;
    }
  }

  sort(T, T + m, cmp1);
  dp[1][600][s] = 0;
  iter = 0;
  for (int t = 600; t >= 0; t--) {
    if (t > 0) {
      rep(u, n) dp[1][t - 1][u] = min(dp[1][t - 1][u], dp[1][t][u]);
    }
    while (iter < m && T[iter].t2 == t) {
      dp[1][T[iter].t1][T[iter].u] =
          min(dp[1][T[iter].t1][T[iter].u], dp[1][t][T[iter].v] + T[iter].cost);
      iter++;
    }
  }
}

int main() {
  for (int m; scanf("%d", &m), m;) {
    int n = 0;
    map<string, int> f;
    f["Hakodate"] = n++;
    f["Tokyo"] = n++;

    train T[2000];
    rep(i, m) {
      char s1[32], t1[8], s2[32], t2[8];
      int cost;
      scanf("%s%s%s%s%d", s1, t1, s2, t2, &cost);
      if (f.count(s1) == 0)
        f[s1] = n++;
      if (f.count(s2) == 0)
        f[s2] = n++;
      int tt1 = decode(t1), tt2 = decode(t2);
      if (0 <= tt1 && tt2 <= 600) {
        T[i] = (train){f[s1], f[s2], tt1, tt2, cost};
      } else {
        i--;
        m--;
      }
    }

    // dp1[0][t][u] := ( 8:00 に函館にいて, 時刻 t に駅 u にいるときの最小コスト
    // ) dp1[1][t][u] := ( 18:00 に函館に戻れて, 時刻 t に駅 u
    // にいるときの最小コスト ) dp2 は dp1 の函館を東京に変えただけ.
    static int dp1[2][601][4000], dp2[2][601][4000];
    calc_time(n, m, T, dp1, 0);
    calc_time(n, m, T, dp2, 1);

    int ans = INF;
    rep(u, n) rep(t, 600 - 30 + 1) {
      ans = min(ans, dp1[0][t][u] + dp1[1][t + 30][u] + dp2[0][t][u] +
                         dp2[1][t + 30][u]);
    }
    printf("%d\\n", ans < INF ? ans : 0);
  }

  return 0;
}