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

#include <algorithm>
#include <climits>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <vector>
using namespace std;

#define REP(i, n) for (int i = 0; i < n; i++)
#define REPA(i, s, e) for (int i = s; i <= e; i++)
#define REPD(i, s, e) for (int i = s; i >= e; i--)

typedef unsigned long long ULL;
typedef vector<int> VI;
typedef pair<int, int> PII;

int n, g;
const int MAX_N = 101;
const int MAX_M = 21;
int m[MAX_N], x[MAX_N][MAX_M], y[MAX_N][MAX_M], c[MAX_N][MAX_M];

const int MAX_V = 5000;      // 最大ノード番号
int v;                       // 通算ノード番号
map<int, int> idx[2][MAX_N]; // 0は入ってくる側，1は出ていく側

struct edge {
  int to;   // 行き先
  int cap;  // 流量
  int cost; // コスト
  int rev;  // 逆辺が格納されている番号
};

vector<edge> G[MAX_V], G2[MAX_V];
int dist[MAX_V];  // ノードまでの最小コスト
int prevv[MAX_V]; // 直前のノード
int preve[MAX_V]; // 直前のエッジ

const int INF = 1000000000;

void add_edge(int from, int to, int cap, int cost) {
  edge e;
  e.to = to, e.cap = cap, e.cost = cost, e.rev = G[to].size();
  G[from].push_back(e);
  e.to = from, e.cap = 0, e.cost = -cost,
  e.rev = G[from].size() -
          1; // 準方向の辺はすでにaddしたので1を引く必要があるのに注意
  G[to].push_back(e);
}

// 最小費用流問題を解く
PII min_cost_flow(int s, int t, int f) {
  for (int i = 0; i < v; i++)
    G2[i] = G[i];
  int res = 0;

  // 流量が限界になるまで流す
  int a = 0; // ゴールについたクラス数
  int b = f; // 最大まで流し切った時のために保存
  while (f > 0) {
    // ダイクストラ法で最短距離を検索
    priority_queue<PII, vector<PII>, greater<PII>> que;
    fill(dist, dist + v, INF);
    dist[s] = 0;
    que.push(PII(0, s));
    while (!que.empty()) {
      PII p = que.top();
      que.pop();
      int nv = p.second;
      if (dist[nv] < p.first)
        continue;

      for (int i = 0; i < G2[nv].size(); i++) {
        edge &e = G2[nv][i];
        if (e.cap > 0 && dist[e.to] > dist[nv] + e.cost) {
          dist[e.to] = dist[nv] + e.cost;
          prevv[e.to] = nv;
          preve[e.to] = i;
          que.push(PII(dist[e.to], e.to));
        }
      }
    }

    if (dist[t] == INF)
      return PII(a, res);

    a++;
    int d = f;
    for (int nv = t; nv != s; nv = prevv[nv]) {
      d = min(d, G2[prevv[nv]][preve[nv]].cap);
    }
    f -= d;
    res += d * dist[t];
    for (int nv = t; nv != s; nv = prevv[nv]) {
      edge &e = G2[prevv[nv]][preve[nv]];
      e.cap = -d;
      G2[nv][e.rev].cap += d;
    }
  }

  return PII(b, res);
}

int main() {
  while (cin >> n, n) {
    // データのクリア
    REP(i, MAX_V) G[i].clear();
    REP(i, 2) REP(j, MAX_N) idx[i][j].clear();

    // データの読み込み
    for (int i = 1; i < n; i++) {
      cin >> m[i];
      REP(j, m[i]) cin >> x[i][j] >> y[i][j] >> c[i][j];
    }
    cin >> g;

    // グラフの作成を開始
    v = 0;
    idx[1][1][0] = v++; // 0番目の駅には0分の時点で着いている
    for (int q = 1; q < n; q++) {
      // q番目の駅から出ていく列車の到着する先にとの間にエッジを張る
      for (map<int, int>::iterator it = idx[1][q].begin();
           it != idx[1][q].end(); ++it) {
        int time = it->first;            // q番目の駅に到着した時間
        for (int j = 0; j < m[q]; j++) { // q番目の駅から出発する列車を調査
          if (x[q][j] >= time) { // 到着した時点でまだ出発していない
            if (idx[0][q + 1].count(y[q][j]) == 0)
              idx[0][q + 1][y[q][j]] =
                  v++; // まだ登場していないノードならノードの番号を追加
            add_edge(it->second, idx[0][q + 1][y[q][j]], 1, c[q][j]);
          }
        }
      }

      // 2つペアで管理されている駅上での発着をエッジで結ぶ
      for (map<int, int>::iterator it = idx[0][q + 1].begin();
           it != idx[0][q + 1].end(); ++it) {
        int time = it->first;
        if (idx[1][q + 1].count(time) == 0)
          idx[1][q + 1][time] =
              v++; // まだ登場していないノードならノードの番号を追加
        add_edge(it->second, idx[1][q + 1][time], 1,
                 0); // 流量を制限するためのノードなのでコストは不要
      }
    }
    idx[0][n + 1][0] = v++;

    // ゴールのノードへエッジを張る
    for (map<int, int>::iterator it = idx[1][n].begin(); it != idx[1][n].end();
         ++it) {
      add_edge(it->second, idx[0][n + 1][0], 1, 0);
    }

    int sp = 0;
    int gp = v - 1;
    PII res = min_cost_flow(sp, gp, g);
    if (res.first != 0) {
      cout << res.first << " " << res.second << endl;
    } else {
      cout << 0 << " " << 0 << endl;
    }
  }
}

Error: MLE

Fixed submission:

#include <algorithm>
#include <climits>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <vector>
using namespace std;

#define REP(i, n) for (int i = 0; i < n; i++)
#define REPA(i, s, e) for (int i = s; i <= e; i++)
#define REPD(i, s, e) for (int i = s; i >= e; i--)

typedef unsigned long long ULL;
typedef vector<int> VI;
typedef pair<int, int> PII;

int n, g;
const int MAX_N = 101;
const int MAX_M = 21;
int m[MAX_N], x[MAX_N][MAX_M], y[MAX_N][MAX_M], c[MAX_N][MAX_M];

const int MAX_V = 5000;      // 最大ノード番号
int v;                       // 通算ノード番号
map<int, int> idx[2][MAX_N]; // 0は入ってくる側，1は出ていく側

struct edge {
  int to;   // 行き先
  int cap;  // 流量
  int cost; // コスト
  int rev;  // 逆辺が格納されている番号
};

vector<edge> G[MAX_V], G2[MAX_V];
int dist[MAX_V];  // ノードまでの最小コスト
int prevv[MAX_V]; // 直前のノード
int preve[MAX_V]; // 直前のエッジ

const int INF = 1000000000;

void add_edge(int from, int to, int cap, int cost) {
  edge e;
  e.to = to, e.cap = cap, e.cost = cost, e.rev = G[to].size();
  G[from].push_back(e);
  e.to = from, e.cap = 0, e.cost = -cost,
  e.rev = G[from].size() -
          1; // 準方向の辺はすでにaddしたので1を引く必要があるのに注意
  G[to].push_back(e);
}

// 最小費用流問題を解く
PII min_cost_flow(int s, int t, int f) {
  for (int i = 0; i < v; i++)
    G2[i] = G[i];
  int res = 0;

  // 流量が限界になるまで流す
  int a = 0; // ゴールについたクラス数
  int b = f; // 最大まで流し切った時のために保存
  while (f > 0) {
    // ダイクストラ法で最短距離を検索
    priority_queue<PII, vector<PII>, greater<PII>> que;
    fill(dist, dist + v, INF);
    dist[s] = 0;
    que.push(PII(0, s));
    while (!que.empty()) {
      PII p = que.top();
      que.pop();
      int nv = p.second;
      if (dist[nv] < p.first)
        continue;

      for (int i = 0; i < G2[nv].size(); i++) {
        edge e = G2[nv][i];
        if (e.cap > 0 && dist[e.to] > dist[nv] + e.cost) {
          dist[e.to] = dist[nv] + e.cost;
          prevv[e.to] = nv;
          preve[e.to] = i;
          que.push(PII(dist[e.to], e.to));
        }
      }
    }

    if (dist[t] == INF)
      return PII(a, res);

    a++;
    int d = f;
    for (int nv = t; nv != s; nv = prevv[nv]) {
      d = min(d, G2[prevv[nv]][preve[nv]].cap);
    }
    f -= d;
    res += d * dist[t];
    for (int nv = t; nv != s; nv = prevv[nv]) {
      edge &e = G2[prevv[nv]][preve[nv]];
      e.cap = -d;
      G2[nv][e.rev].cap += d;
    }
  }

  return PII(b, res);
}

int main() {
  while (cin >> n, n) {
    // データのクリア
    REP(i, MAX_V) G[i].clear();
    REP(i, 2) REP(j, n) idx[i][j].clear();

    // データの読み込み
    for (int i = 1; i < n; i++) {
      cin >> m[i];
      REP(j, m[i]) cin >> x[i][j] >> y[i][j] >> c[i][j];
    }
    cin >> g;

    // グラフの作成を開始
    v = 0;
    idx[1][1][0] = v++; // 0番目の駅には0分の時点で着いている
    for (int q = 1; q < n; q++) {
      // q番目の駅から出ていく列車の到着する先にとの間にエッジを張る
      for (map<int, int>::iterator it = idx[1][q].begin();
           it != idx[1][q].end(); ++it) {
        int time = it->first;            // q番目の駅に到着した時間
        for (int j = 0; j < m[q]; j++) { // q番目の駅から出発する列車を調査
          if (x[q][j] >= time) { // 到着した時点でまだ出発していない
            if (idx[0][q + 1].count(y[q][j]) == 0)
              idx[0][q + 1][y[q][j]] =
                  v++; // まだ登場していないノードならノードの番号を追加
            add_edge(it->second, idx[0][q + 1][y[q][j]], 1, c[q][j]);
          }
        }
      }

      // 2つペアで管理されている駅上での発着をエッジで結ぶ
      for (map<int, int>::iterator it = idx[0][q + 1].begin();
           it != idx[0][q + 1].end(); ++it) {
        int time = it->first;
        if (idx[1][q + 1].count(time) == 0)
          idx[1][q + 1][time] =
              v++; // まだ登場していないノードならノードの番号を追加
        add_edge(it->second, idx[1][q + 1][time], 1,
                 0); // 流量を制限するためのノードなのでコストは不要
      }
    }
    idx[0][n + 1][0] = v++;

    // ゴールのノードへエッジを張る
    for (map<int, int>::iterator it = idx[1][n].begin(); it != idx[1][n].end();
         ++it) {
      add_edge(it->second, idx[0][n + 1][0], 1, 0);
    }

    int sp = 0;
    int gp = v - 1;
    PII res = min_cost_flow(sp, gp, g);
    if (res.first != 0) {
      cout << res.first << " " << res.second << endl;
    } else {
      cout << 0 << " " << 0 << endl;
    }
  }
}