Problem p01269 (C++) — buggy submission, verdict: Time Limit Exceeded

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

const int MAX_N = 101;
const int INF = 1e+8;
typedef pair<int, int> P;

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

// 宿の数
int N;
// G[u] := ノード u と隣接するエッジのvectorを返す
vector<edge> G[MAX_N];
// 頂点 v := <宿の番号,持っているお金>, memo[v] := v の最小コスト
map<P, int> memo;

// 初期化
void init() {
  for (int i = 0; i < MAX_N; i++) {
    G[i].clear();
  }
  for (int i = 0; i < MAX_N; i++) {
    for (int j = 0; j < MAX_N; j++) {
      memo[P(i, j)] = INF;
    }
  }
}

// 辺の追加
void add_edge(int u, int v, int d, int cost) {
  edge e(v, d, cost);
  G[u].push_back(e);
  e.to = u;
  G[v].push_back(e);
}

// 探索
int bfs(int s, int L) {
  // (今まで襲われた数,宿の番号,今持っているお金) の状態を持つ優先度付きキュー
  priority_queue<pair<int, P>, vector<pair<int, P>>, greater<pair<int, P>>> q;
  // 襲われた数 0, 宿 s から お金 L の状態でスタートする
  P sp(s, L);
  pair<int, P> start(0, sp);
  q.push(start);
  memo[sp] = 0;

  int ans = INF;
  while (!q.empty()) {
    // now_cost := 今まで襲われた数
    int now_cost = q.top().first;
    P now = q.top().second;
    q.pop();
    // v := 今いる宿
    int v = now.first;
    // l := 今持っているお金
    int l = now.second;

    // ゴールにいるとき
    if (v == N - 1) {
      ans = min(ans, now_cost);
      continue;
    }

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

      // 距離以上のお金があるとき
      if (d <= l) {
        // to : 次の宿, l-d : 持っているお金
        P next(to, l - d);
        int next_cost = now_cost + 0;
        if (next_cost < memo[next]) {
          memo[next] = next_cost;
          pair<int, P> p(next_cost, next);
          q.push(p);
        }
      }
      // お金を払わず進むとき
      {
        // to : 次の宿, l : 持っているお金
        P next(to, l);
        int next_cost = now_cost + G[v][i].cost;
        if (next_cost < memo[next]) {
          memo[next] = next_cost;
          pair<int, P> p(next_cost, next);
          q.push(p);
        }
      }
    }
  }
  return ans;
}

int main() {
  int M, L;
  while (cin >> N >> M >> L, N || M || L) {
    init();

    for (int i = 0; i < M; i++) {
      int a, b, d, e;
      cin >> a >> b >> d >> e;
      a--;
      b--;
      add_edge(a, b, d, e);
    }
    int ans = bfs(0, L);
    cout << ans << endl;
  }
}

Error: TLE

Fixed submission:

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

const int MAX_N = 101;
const int MAX_V = 10000;
const int INF = 1e+8;
typedef pair<int, int> P;

struct edge {
  int to, d, e;
  edge(int v_, int d_, int e_) {
    to = v_;
    d = d_;
    e = e_;
  };
};

// g[u] := ノード u と隣接するエッジのvectorを返す
vector<edge> g[MAX_N];
// G[u] := ノード u と隣接するエッジのvectorを返す (解を求めるために使うグラフ)
vector<edge> G[MAX_V];
// p = (頂点,持っているお金)をひとつの頂点とみなし, h[p]
// で対応する頂点番号を返す
map<P, int> h;
// N : 宿の数, id: 生成する頂点番号の管理に使う
int N, id;
// d[v] := 始点から頂点 v までの最短距離
int d[MAX_V];

// デバッグ用
void debug(vector<int> path) {
  for (map<P, int>::iterator it = h.begin(); it != h.end(); ++it) {
    cout << "<" << (it->first).first << "," << (it->first).second << ">";
    cout << " = " << it->second << endl;
  }
  for (int i = 0; i < path.size(); i++) {
    cout << path[i];
    if (i != path.size() - 1)
      cout << " => ";
  }
  cout << endl;
}

void debug_2() {
  cout << "[debug]" << endl;
  for (int v = 0; v < id; v++) {
    for (int i = 0; i < G[v].size(); i++) {
      edge ed = G[v][i];
      cout << "(" << v << "," << ed.to << ") = " << ed.e << endl;
    }
  }
  cout << endl;
}

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

// 辺の追加
void add_edge(int u, int v, int d, int e) {
  edge ed(v, d, e);
  g[u].push_back(ed);
  ed.to = u;
  g[v].push_back(ed);
}

// 辺の追加2
bool add_edge2(int u, int v, int cost) {
  bool flag = false;
  for (int i = 0; i < G[u].size(); i++) {
    if (G[u][i].to == v) {
      flag = true;
    }
  }
  if (flag)
    return false;
  edge ed(v, 0, cost);
  G[u].push_back(ed);
  // ed.to = u;
  // G[v].push_back( ed );
  return true;
}

// <頂点番号,持っているお金>を頂点,
// 襲われる人数をエッジのコストとしたグラフをつくる
void dfs(int v, int L, map<int, bool> memo) {
  if (v == N - 1)
    return;

  P from(v, L);
  if (!h.count(from)) {
    h[from] = id;
    id++;
  }
  int a = h[from];

  for (int i = 0; i < g[v].size(); i++) {
    edge ed = g[v][i];
    if (memo.count(ed.to) && memo[ed.to])
      continue;
    memo[ed.to] = true;

    P next_1(ed.to, L);
    if (!h.count(next_1)) {
      h[next_1] = id;
      id++;
    }
    int b = h[next_1];
    bool flag = add_edge2(a, b, ed.e);
    if (flag)
      dfs(ed.to, L, memo);

    if (L >= ed.d) {
      P next_2(ed.to, L - ed.d);
      if (!h.count(next_2)) {
        h[next_2] = id;
        id++;
      }
      int c = h[next_2];
      flag = add_edge2(a, c, 0);
      if (flag)
        dfs(ed.to, L - ed.d, memo);
    }
    memo[ed.to] = false;
  }
}

// ダイクストラ法
void dijkstra() {
  priority_queue<P, vector<P>, greater<P>> q;
  fill(d, d + MAX_V, INF);
  d[0] = 0;
  q.push(P(0, 0));
  while (!q.empty()) {
    P p = q.top();
    q.pop();
    int v = p.second;

    if (d[v] < p.first)
      continue;
    for (int i = 0; i < G[v].size(); i++) {
      edge ed = G[v][i];
      if (d[ed.to] > d[v] + ed.e) {
        d[ed.to] = d[v] + ed.e;
        q.push(P(d[ed.to], ed.to));
      }
    }
  }
}

// 最小値を求める
int solve() {
  int ans = INF;
  for (map<P, int>::iterator it = h.begin(); it != h.end(); ++it) {
    if ((it->first).first == N - 1) {
      int v = h[it->first];
      ans = min(ans, d[v]);
    }
  }
  return ans;
}

int main() {
  int M, L;
  while (cin >> N >> M >> L, N || M || L) {
    init();

    for (int i = 0; i < M; i++) {
      int a, b, d, e;
      cin >> a >> b >> d >> e;
      a--;
      b--;
      add_edge(a, b, d, e);
    }

    // グラフの生成
    id = 0;
    map<int, bool> memo;
    memo[0] = true;
    dfs(0, L, memo);
    // ダイクストラ法
    dijkstra();
    // 最小コストを求める
    int ans = solve();
    cout << ans << endl;
  }
}