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

#include <algorithm>
#include <iostream>
#include <map>
#include <queue>
#include <vector>
using namespace std;

const int MAX_N = 8;
const int MAX_V = 10000;
const int MAX_CITY = 31;
const double INF = 1e+8;
typedef pair<int, int> P;
typedef pair<double, P> State;

struct edge {
  int to, d;
  edge(int to_, int d_) {
    to = to_;
    d = d_;
  };
};

// 馬車券の数
int n;
// t[i] := i 番目の馬車券の馬の数
int t[MAX_N];
// グラフ
vector<edge> G[MAX_V];
// 町の数
int V;

// 初期化
void init() {
  for (int i = 0; i < MAX_V; i++) {
    G[i].clear();
  }
}

void add_edge(int u, int v, int d) {
  edge e(v, d);
  G[u].push_back(e);
  e.to = u;
  G[v].push_back(e);
}

// 辿りつけるかどうか
bool search(int s, int g) {
  map<int, bool> memo;
  for (int i = 0; i < MAX_CITY; i++) {
    memo[i] = false;
  }
  queue<P> q;
  q.push(P(s, 0));

  while (!q.empty()) {
    int v = q.front().first;
    int cnt = q.front().second;
    q.pop();

    memo[v] = true;
    if (v == g) {
      return true;
    }
    if (cnt > n)
      continue;

    for (int i = 0; i < G[v].size(); i++) {
      int to = G[v][i].to;
      P next(to, cnt + 1);
      if (!memo[to]) {
        q.push(next);
      }
    }
  }
  return false;
}

// s : スタート, g : ゴール
double bfs(int s, int g) {

  // d[v][bits] := 頂点 (v,bits) までの最小コスト
  double d[MAX_CITY][1 << MAX_N];
  // 訪れたかどうか
  bool visited[MAX_CITY][1 << MAX_N];

  // 初期化
  for (int i = 0; i < MAX_CITY; i++) {
    for (int bits = 0; bits < (1 << MAX_N); bits++) {
      d[i][bits] = INF;
      visited[i][bits] = false;
    }
  }

  // 頂点 : (今いる町の番号,馬車券の持っている状態)
  // 馬車券の持っている状態は bit列で表現
  // ((1<<n)-1) == 2^n -1
  P start(s, ((1 << n) - 1));

  // 優先度付きキュー
  // state : ( コスト , (町番号,馬車券の状態) )
  priority_queue<State, vector<State>, greater<State>> q;
  q.push(State(0.0, start));
  d[s][(1 << n) - 1] = 0.0;

  // 答え
  double ans = INF;
  while (!q.empty()) {
    // 取り出す
    double now_cost = q.top().first;
    int v = q.top().second.first;
    int bits = q.top().second.second;
    P now(v, bits);
    q.pop();

    if (visited[v][bits])
      continue;
    visited[v][bits] = true;

    if (v == g) {
      ans = min(ans, now_cost);
      break;
    }

    for (int i = 0; i < G[v].size(); i++) {
      int to = G[v][i].to;
      int dist = G[v][i].d;

      for (int i = 0; i < n; i++) {
        // i 番目の馬車券があるとき
        if ((bits & (1 << i))) {
          int next_bits = bits - (1 << i);
          P next(to, next_bits);
          double cost = (double)dist / t[i];

          if (now_cost + cost < d[to][next_bits]) {
            d[to][next_bits] = now_cost + cost;
            q.push(State(now_cost + cost, next));
          }
        }
      }
    }
  }
  return ans;
}

int main() {
  int m, p, s, g;
  while (cin >> n >> m >> p >> s >> g, n) {
    s--;
    g--;
    V = m;
    init();

    for (int i = 0; i < n; i++) {
      cin >> t[i];
    }
    for (int i = 0; i < p; i++) {
      int x, y, d;
      cin >> x >> y >> d;
      add_edge(x - 1, y - 1, d);
    }
    // ゴールに到達できるかどうか
    bool is_goal = search(s, g);

    if (is_goal) {
      double ans = bfs(s, g);
      if (ans == INF)
        cout << "Impossible" << endl;
      else
        cout << ans << endl;
    } else {
      cout << "Impossible" << endl;
    }
  }
}

Error: MLE

Fixed submission:

#include <algorithm>
#include <iostream>
#include <map>
#include <queue>
#include <vector>
using namespace std;

const int MAX_N = 8;
const int MAX_V = 10000;
const int MAX_CITY = 31;
const double INF = 1e+8;
typedef pair<int, int> P;
typedef pair<double, pair<int, P>> state;

struct edge {
  int to, d;
  edge(int to_, int d_) {
    to = to_;
    d = d_;
  };
};

// 馬車券の数
int n;
// t[i] := i 番目の馬車券の馬の数
int t[MAX_N];
// グラフ
vector<edge> G[MAX_V];
// 町の数
int V;

// 初期化
void init() {
  for (int i = 0; i < MAX_V; i++) {
    G[i].clear();
  }
}

void add_edge(int u, int v, int d) {
  edge e(v, d);
  G[u].push_back(e);
  e.to = u;
  G[v].push_back(e);
}

// 辿りつけるかどうか
bool search(int s, int g) {
  map<int, bool> memo;
  for (int i = 0; i < MAX_CITY; i++) {
    memo[i] = false;
  }
  queue<P> q;
  q.push(P(s, 0));

  while (!q.empty()) {
    int v = q.front().first;
    int cnt = q.front().second;
    q.pop();

    memo[v] = true;
    if (v == g) {
      return true;
    }
    if (cnt > n)
      continue;

    for (int i = 0; i < G[v].size(); i++) {
      int to = G[v][i].to;
      P next(to, cnt + 1);
      if (!memo[to]) {
        q.push(next);
      }
    }
  }
  return false;
}

// s : スタート, g : ゴール
double bfs(int s, int g) {
  // 答え
  double ans = INF;
  // (今いる町の番号,馬車券の持っている状態) を頂点とする
  // 馬車券の持っている状態は bit列で表現
  // ((1<<n)-1) == 2^n -1
  P p1(s, ((1 << n) - 1));
  // d[v] := 頂点 v までの最小コスト
  map<P, double> d;
  // 初期化
  for (int i = 0; i < V; i++) {
    for (int bits = 0; bits < (1 << n); bits++) {
      d[P(i, bits)] = INF;
    }
  }

  // 優先度付きキュー
  // state : ( コスト , ( 今まで訪れた町, (町番号,馬車券の状態)) )
  priority_queue<state, vector<state>, greater<state>> q;
  pair<int, P> p_((1 << s), p1);
  state start(0.0, p_);
  q.push(start);
  d[p1] = 0.0;

  while (!q.empty()) {
    double now_cost = q.top().first;
    int visited = q.top().second.first;
    int v = q.top().second.second.first;
    int bits = q.top().second.second.second;
    P now(v, bits);
    q.pop();

    if (v == g) {
      ans = min(ans, now_cost);
      continue;
    }

    for (int i = 0; i < G[v].size(); i++) {
      int to = G[v][i].to;
      int dist = G[v][i].d;

      for (int i = 0; i < n; i++) {
        // i 番目の馬車券があってまだ訪れてない町のとき
        if ((bits & (1 << i)) && !(visited & (1 << to))) {
          int next_visited = visited | (1 << to);
          int next_bits = bits - (1 << i);
          double cost = (double)dist / t[i];
          P p2(to, next_bits);
          pair<int, P> next(next_visited, p2);
          if (now_cost + cost < d[p2]) {
            d[p2] = now_cost + cost;
            q.push(state(d[p2], next));
          }
        }
      }
    }
  }
  return ans;
}

int main() {
  int m, p, s, g;
  while (cin >> n >> m >> p >> s >> g, n) {
    s--;
    g--;
    V = m;
    init();

    for (int i = 0; i < n; i++) {
      cin >> t[i];
    }
    for (int i = 0; i < p; i++) {
      int x, y, d;
      cin >> x >> y >> d;
      add_edge(x - 1, y - 1, d);
    }
    // ゴールに到達できるかどうか
    bool is_goal = search(s, g);

    if (is_goal) {
      double ans = bfs(s, g);
      if (ans == INF)
        cout << "Impossible" << endl;
      else
        cout << ans << endl;
    } else {
      cout << "Impossible" << endl;
    }
  }
}