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

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

typedef pair<int, int> P;
const int MAX_W = 20;
const int MAX_H = 20;
const int MAX_N = 10;
const int INF = 1e+8;

int w, h;
int dx[4] = {0, 0, 1, -1};
int dy[4] = {1, -1, 0, 0};
int d[MAX_H][MAX_W];
int g[MAX_N][MAX_N];

void debug(int n) {
  cout << "[debug]" << endl;
  for (int i = 0; i < n; i++) {
    for (int j = 0; j < n; j++) {
      if (g[i][j] == INF)
        cout << -1 << "  ";
      else
        cout << g[i][j] << "  ";
    }
    cout << endl;
  }
  cout << endl;
}

void init() {
  for (int i = 0; i < MAX_N; i++) {
    for (int j = 0; j < MAX_N; j++) {
      g[i][j] = INF;
    }
  }
}

void clear_d() {
  for (int y = 0; y < MAX_H; y++) {
    for (int x = 0; x < MAX_W; x++) {
      d[y][x] = INF;
    }
  }
}

// 文字 c がある座標の位置を求める
void search(const vector<string> &m, vector<P> &vp, char c) {
  for (int y = 0; y < h; y++) {
    for (int x = 0; x < w; x++) {
      if (m[y][x] == c) {
        vp.push_back(P(x, y));
      }
    }
  }
}

// spから汚れたタイルまでの距離を調べる
void bfs(const vector<string> &m, P sp, map<P, int> f) {
  d[sp.second][sp.first] = 0;
  queue<P> q;
  q.push(sp);
  while (!q.empty()) {
    P p = q.front();
    q.pop();
    int cnt = d[p.second][p.first];
    for (int i = 0; i < 4; i++) {
      int mx = p.first + dx[i];
      int my = p.second + dy[i];
      if (mx < 0 || my < 0 || mx >= w || my >= h || m[my][mx] == 'x') {
        continue;
      }
      if (d[my][mx] == INF) {
        if (m[my][mx] == '*') {
          int u = f[sp];
          int v = f[P(mx, my)];
          g[u][v] = g[v][u] = cnt + 1;
        }
        d[my][mx] = cnt + 1;
        q.push(P(mx, my));
      }
    }
  }
}

int main() {
  while (cin >> w >> h, w || h) {
    // 初期化
    init();
    // m[y][x] := (x,y)の状態
    vector<string> m(h);
    // vp[i] := i 番目の汚れたタイルの座標
    vector<P> vp;
    // f[p] := 座標 p と対応する i を返す (i番目の汚れたタイル)
    map<P, int> f;

    // 入力
    for (int y = 0; y < h; y++) {
      cin >> m[y];
    }
    // スタート地点と汚れたタイルの位置を調べる
    search(m, vp, '*');
    search(m, vp, 'o');
    for (int i = 0; i < vp.size(); i++) {
      f[vp[i]] = i;
    }
    // 各汚れたタイル同士の距離を調べる
    for (int i = 0; i < vp.size(); i++) {
      clear_d();
      bfs(m, vp[i], f);
    }
    // debug( vp.size() );

    // dp[s][v] := s は訪れたかどうかのbit列, v は最後に訪れたマス
    int dp[1 << 10][10];
    int N = vp.size() - 1;
    // 初期化
    for (int i = 0; i < (1 << N); i++) {
      for (int j = 0; j < N; j++) {
        dp[i][j] = INF;
      }
    }
    // スタートから i までの距離
    int start = N;
    for (int i = 0; i < N; i++) {
      dp[1 << i][i] = g[N][i];
    }
    for (int s = 0; s < (1 << N); s++) {
      for (int u = 0; u < N; u++) {
        for (int v = 0; v < N; v++) {
          dp[s | 1 << v][v] = min(dp[s | 1 << v][v], dp[s][u] + g[u][v]);
        }
      }
    }
    int ans = INF;
    for (int i = 0; i < N; i++) {
      ans = min(ans, dp[(1 << N) - 1][i]);
    }
    if (ans == INF)
      cout << -1 << endl;
    else
      cout << ans << endl;
  }
}

Error: TLE

Fixed submission:

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

typedef pair<int, int> P;
const int MAX_W = 20;
const int MAX_H = 20;
const int MAX_N = 10;
const int INF = 1e+8;

int w, h;
int dx[4] = {0, 0, 1, -1};
int dy[4] = {1, -1, 0, 0};
int d[MAX_H][MAX_W];
int g[MAX_N][MAX_N];
int ans;

void debug(int n) {
  cout << "[debug]" << endl;
  for (int i = 0; i < n; i++) {
    for (int j = 0; j < n; j++) {
      if (g[i][j] == INF)
        cout << -1 << "  ";
      else
        cout << g[i][j] << "  ";
    }
    cout << endl;
  }
  cout << endl;
}

void init() {
  for (int i = 0; i < MAX_N; i++) {
    for (int j = 0; j < MAX_N; j++) {
      g[i][j] = INF;
    }
  }
}

void clear_d() {
  for (int y = 0; y < MAX_H; y++) {
    for (int x = 0; x < MAX_W; x++) {
      d[y][x] = INF;
    }
  }
}

// 文字 c がある座標の位置を求める
void search(const vector<string> &m, vector<P> &vp, char c) {
  for (int y = 0; y < h; y++) {
    for (int x = 0; x < w; x++) {
      if (m[y][x] == c) {
        vp.push_back(P(x, y));
      }
    }
  }
}

// spから汚れたタイルまでの距離を調べる
void bfs(const vector<string> &m, P sp, map<P, int> f) {
  d[sp.second][sp.first] = 0;
  queue<P> q;
  q.push(sp);
  while (!q.empty()) {
    P p = q.front();
    q.pop();
    int cnt = d[p.second][p.first];
    for (int i = 0; i < 4; i++) {
      int mx = p.first + dx[i];
      int my = p.second + dy[i];
      if (mx < 0 || my < 0 || mx >= w || my >= h || m[my][mx] == 'x') {
        continue;
      }
      if (d[my][mx] == INF) {
        if (m[my][mx] == '*') {
          int u = f[sp];
          int v = f[P(mx, my)];
          g[u][v] = g[v][u] = cnt + 1;
        }
        d[my][mx] = cnt + 1;
        q.push(P(mx, my));
      }
    }
  }
}

void dfs(int N, int v, int cnt, int sum, map<int, bool> memo) {
  if (N == cnt) {
    ans = min(ans, sum);
    return;
  }
  for (int u = 1; u < N; u++) {
    if (u == v)
      continue;
    if (!memo[u]) {
      memo[u] = true;
      dfs(N, u, cnt + 1, sum + g[v][u], memo);
      memo[u] = false;
    }
  }
}

int main() {
  while (cin >> w >> h, w || h) {
    // 初期化
    init();
    // m[y][x] := (x,y)の状態
    vector<string> m(h);
    // vp[i] := i 番目の汚れたタイルの座標 (i=0 はスタート地点)
    vector<P> vp;
    // f[p] := 座標 p と対応する i を返す (i番目の汚れたタイル)
    map<P, int> f;

    // 入力
    for (int y = 0; y < h; y++) {
      cin >> m[y];
    }
    // スタート地点と汚れたタイルの位置を調べる
    search(m, vp, 'o');
    search(m, vp, '*');
    for (int i = 0; i < vp.size(); i++) {
      f[vp[i]] = i;
    }
    // 各汚れたタイル同士の距離を調べる
    for (int i = 0; i < vp.size(); i++) {
      clear_d();
      bfs(m, vp[i], f);
    }
    // debug( vp.size() );

    // 最短距離を求める
    map<int, bool> memo;
    for (int i = 1; i < vp.size(); i++)
      memo[i] = false;
    memo[0] = true;
    ans = INF;
    dfs(vp.size(), 0, 1, 0, memo);
    if (ans == INF)
      cout << -1 << endl;
    else
      cout << ans << endl;
  }
}