Problem p00721 (C++)

Buggy submission (status: Runtime Error):
#include <algorithm>
#include <cstdio>
#include <iostream>
#include <math.h>
#include <queue>
#include <set>
#include <stack>
#include <string.h>
#include <string>
using namespace std;

#define FOR(i, n) for (int i = 0; i < n; i++)
#define bit(i) static_cast<bitset<8>>(i)

typedef long long ll;
typedef unsigned long long ull;
typedef vector<int> VI;
typedef vector<string> VS;
typedef pair<int, int> PII;
typedef pair<long long, long long> PLL;
typedef queue<int> QI;
typedef priority_queue<int> maxpq;
typedef priority_queue<int, vector<int>, greater<int>> minpq;

struct edge {
  int to, cost;
};

void begin() {
  cin.tie(0);
  ios::sync_with_stdio(false);
};
int gcd(int a, int b) {
  if (a % b == 0) {
    return (b);
  } else {
    return (gcd(b, a % b));
  }
};
int lcm(int m, int n) {
  if ((0 == m) || (0 == n)) {
    return 0;
  }
  return ((m / gcd(m, n)) * n);
};
unsigned long long comb(long n, long m) {
  unsigned long long c = 1;
  m = (n - m < m ? n - m : m);
  for (long ns = n - m + 1, ms = 1; ms <= m; ns++, ms++) {
    c *= ns;
    c /= ms;
  }
  return c;
};

void cp(int a1[], int a2[], int l) { FOR(i, l) a2[i] = a1[i]; };
double sq(double d) { return d * d; };
int sq(int i) { return i * i; };
double sqdist(int x1, int y1, int x2, int y2) {
  double dx = x1 - x2, dy = y1 - y2;
  return dx * dx + dy * dy;
};

// ワーシャルフロイド法
void warshallFloyd(int d[100][100], int n) {
  for (int k = 0; k < n; ++k)
    for (int i = 0; i < n; ++i)
      for (int j = 0; j < n; ++j)
        if (d[i][k] != -1 && d[k][j] != -1) {
          if (d[i][j] == -1) {
            d[i][j] = d[i][k] + d[k][j];
          } else {
            d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
          }
        }
};

// d:隣接行列  n:グラフのサイズ  s:始点  dist:始点からの距離が入る配列
void dijkstra(int d[1000][1000], int n, int s, int dist[1000]) {
  FOR(i, n) dist[i] = -1;
  dist[s] = 0;
  priority_queue<PII, vector<PII>, greater<PII>> q;
  q.push(PII(0, s));
  while (!q.empty()) {
    PII p = q.top();
    q.pop();
    int i = p.second;
    if (dist[i] < p.first)
      continue;
    for (int j = 0; j < n; j++) {
      if (d[i][j] == -1)
        continue;
      if (dist[j] == -1) {
        dist[j] = dist[i] + d[i][j];
        q.push(PII(dist[j], j));
      } else if (dist[j] > dist[i] + d[i][j]) {
        dist[j] = dist[i] + d[i][j];
        q.push(PII(dist[j], j));
      }
    }
  }
};

// 線分の交差判定
bool isCross(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4) {
  // 並行な場合
  int m = (x2 - x1) * (y4 - y3) - (y2 - y1) * (x4 - x3);
  if (m == 0)
    return false;
  // 媒介変数の値が0より大きく1以下なら交差する、これは問題の状況によって変わるかも。
  double r = (double)((y4 - y3) * (x3 - x1) - (x4 - x3) * (y3 - y1)) / m;
  double s = (double)((y2 - y1) * (x3 - x1) - (x2 - x1) * (y3 - y1)) / m;
  return (0 < r && r <= 1 && 0 < s && s <= 1);
};

// 外積の計算 AB CD の内積を求める
int crossProdct(int ax, int ay, int bx, int by, int cx, int cy, int dx,
                int dy) {
  int abx = bx - ax;
  int aby = by - ay;
  int cdx = dx - cx;
  int cdy = dy - cy;
  return abx * cdy - cdx * aby;
};
double crossProdct(double ax, double ay, double bx, double by, double cx,
                   double cy, double dx, double dy) {
  double abx = bx - ax;
  double aby = by - ay;
  double cdx = dx - cx;
  double cdy = dy - cy;
  return abx * cdy - cdx * aby;
};
double innerProduct(double ax, double ay, double bx, double by, double cx,
                    double cy, double dx, double dy) {
  double abx = bx - ax;
  double aby = by - ay;
  double cdx = dx - cx;
  double cdy = dy - cy;
  return abx * cdx + aby * cdy;
};

// 三角形の内部判定 ABCの中にPがあるか判定
bool inTriangle(int ax, int ay, int bx, int by, int cx, int cy, int px,
                int py) {
  int c1 = crossProdct(ax, ay, bx, by, bx, by, px, py);
  int c2 = crossProdct(bx, by, cx, cy, cx, cy, px, py);
  int c3 = crossProdct(cx, cy, ax, ay, ax, ay, px, py);
  return (c1 > 0 && c2 > 0 && c3 > 0) || (c1 < 0 && c2 < 0 && c3 < 0);
};
bool inTriangle(double ax, double ay, double bx, double by, double cx,
                double cy, double px, double py) {
  double c1 = crossProdct(ax, ay, bx, by, bx, by, px, py);
  double c2 = crossProdct(bx, by, cx, cy, cx, cy, px, py);
  double c3 = crossProdct(cx, cy, ax, ay, ax, ay, px, py);
  return (c1 > 0 && c2 > 0 && c3 > 0) || (c1 < 0 && c2 < 0 && c3 < 0);
};

// 三角形の外心
void circumcenter(double ax, double ay, double bx, double by, double cx,
                  double cy, double res[3]) {
  // AB AC を求める
  double abx = bx - ax;
  double aby = by - ay;
  double acx = cx - ax;
  double acy = cy - ay;
  double m =
      abx * acy - acx * aby; // 分母 m = 0 となるのは3点が一直線になるとき
  double s = (abx * acx + aby * acy - sq(acx) - sq(acy)) / m; // 媒介変数s
  res[0] = abx / 2 + s * aby / 2;
  res[1] = aby / 2 - s * abx / 2;
  // cout << res[0] << " " << res[1] << endl;
  res[2] = sqrt(sqdist(0, 0, res[0], res[1]));
  res[0] += ax;
  res[1] += ay;
};

/**
 * start
 * @author yoshikyoto
 */
int w, h;
string tile[20];
int dist[20][20];
int g[11][11];
int sx[11], sy[11];
int dp[1024][11];
int vy[4] = {-1, 1, 0, 0}, vx[4] = {0, 0, -1, 1};

int dcount = 1;
int p[11];

void dfs(int hist, int curr) {
  for (int next = 1; next < dcount; next++) {
    if (hist & p[next])
      continue; // 既に訪れている
    // 訪れていない
    int next_hist = hist | p[next];
    int cost = dp[hist][curr] + g[curr][next];
    if (cost < dp[next_hist][next] || dp[next_hist][next] == -1) {
      dp[next_hist][next] = cost;
      dfs(next_hist, next);
    }
  }
};

void solve() {
  FOR(i, h) cin >> tile[i];

  // 配列をなめて汚れたタイルの位置を獲得、汚れに番号をつける
  FOR(i, h) FOR(j, w) {
    if (tile[i][j] == '*') {
      sy[dcount] = i;
      sx[dcount] = j;
      tile[i][j] = (char)('0' + dcount); // 汚れに番号を付ける
      dcount++;
    } else if (tile[i][j] == 'o') {
      // 自分の位置
      sy[0] = i;
      sx[0] = j;
      tile[i][j] = '0';
    }
  }
  // グラフの初期化
  FOR(i, dcount) FOR(j, dcount) g[i][j] = -1;
  // FOR(i, h) cout << tile[i] << endl;

  // まずはbfsしてグラフを生成する
  FOR(i, dcount) {
    FOR(k, h) FOR(l, w) dist[k][l] = -1;
    dist[sy[i]][sx[i]] = 0;
    QI yq, xq;
    yq.push(sy[i]);
    xq.push(sx[i]);
    int checked = 1;
    while (checked < dcount && !yq.empty()) {
      int y = yq.front();
      yq.pop();
      int x = xq.front();
      xq.pop();

      // 上下左右を見る
      FOR(j, 4) {
        int ny = y + vy[j], nx = x + vx[j]; // nexty, nextx;
        if (dist[ny][nx] > -1)
          continue; // 既に訪れた場合
        if (ny < 0 || ny > h - 1 || nx < 0 || nx > w - 1)
          continue; // 部屋を出てしまう場合
        int dnum = (int)tile[ny][nx] - '0';
        if (tile[ny][nx] != 'x') {
          // 障害物でない場合
          yq.push(ny);
          xq.push(nx);
          dist[ny][nx] = dist[y][x] + 1;
          // グラフに追加したい場
          if (0 <= dnum && dnum < dcount) {
            g[i][dnum] = dist[ny][nx];
            checked++;
          }
        }
      }
    }
  }

  /*
  FOR(i, dcount){
      FOR(j, dcount){
          cout << g[i][j] << " ";
      }
      cout << endl;
  }
   */

  // 行けないところがあったらダメ
  for (int i = 1; i < dcount; i++)
    if (g[0][i] == -1) {
      cout << -1 << endl;
      return;
    }

  // メモ化再帰
  FOR(i, 1024) FOR(j, 11) dp[i][j] = -1;
  FOR(i, dcount) p[i] = (int)pow(2, i);
  dp[1][0] = 0;
  dfs(1, 0);

  int final = 1;
  for (int i = 1; i < dcount; i++)
    final += p[i];

  int ans = dp[final][1];
  for (int i = 2; i < dcount; i++) {
    ans = min(ans, dp[final][i]);
  }
  cout << ans << endl;
};

int main(int argc, const char *argv[]) {
  begin();
  while (true) {
    cin >> w >> h;
    if (w == 0 && h == 0)
      break;
    solve();
  }
}

Fixed submission:
#include <algorithm>
#include <cstdio>
#include <iostream>
#include <math.h>
#include <queue>
#include <set>
#include <stack>
#include <string.h>
#include <string>
using namespace std;

#define FOR(i, n) for (int i = 0; i < n; i++)
#define bit(i) static_cast<bitset<8>>(i)

typedef long long ll;
typedef unsigned long long ull;
typedef vector<int> VI;
typedef vector<string> VS;
typedef pair<int, int> PII;
typedef pair<long long, long long> PLL;
typedef queue<int> QI;
typedef priority_queue<int> maxpq;
typedef priority_queue<int, vector<int>, greater<int>> minpq;

struct edge {
  int to, cost;
};

void begin() {
  cin.tie(0);
  ios::sync_with_stdio(false);
};
int gcd(int a, int b) {
  if (a % b == 0) {
    return (b);
  } else {
    return (gcd(b, a % b));
  }
};
int lcm(int m, int n) {
  if ((0 == m) || (0 == n)) {
    return 0;
  }
  return ((m / gcd(m, n)) * n);
};
unsigned long long comb(long n, long m) {
  unsigned long long c = 1;
  m = (n - m < m ? n - m : m);
  for (long ns = n - m + 1, ms = 1; ms <= m; ns++, ms++) {
    c *= ns;
    c /= ms;
  }
  return c;
};

void cp(int a1[], int a2[], int l) { FOR(i, l) a2[i] = a1[i]; };
double sq(double d) { return d * d; };
int sq(int i) { return i * i; };
double sqdist(int x1, int y1, int x2, int y2) {
  double dx = x1 - x2, dy = y1 - y2;
  return dx * dx + dy * dy;
};

// ワーシャルフロイド法
void warshallFloyd(int d[100][100], int n) {
  for (int k = 0; k < n; ++k)
    for (int i = 0; i < n; ++i)
      for (int j = 0; j < n; ++j)
        if (d[i][k] != -1 && d[k][j] != -1) {
          if (d[i][j] == -1) {
            d[i][j] = d[i][k] + d[k][j];
          } else {
            d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
          }
        }
};

// d:隣接行列  n:グラフのサイズ  s:始点  dist:始点からの距離が入る配列
void dijkstra(int d[1000][1000], int n, int s, int dist[1000]) {
  FOR(i, n) dist[i] = -1;
  dist[s] = 0;
  priority_queue<PII, vector<PII>, greater<PII>> q;
  q.push(PII(0, s));
  while (!q.empty()) {
    PII p = q.top();
    q.pop();
    int i = p.second;
    if (dist[i] < p.first)
      continue;
    for (int j = 0; j < n; j++) {
      if (d[i][j] == -1)
        continue;
      if (dist[j] == -1) {
        dist[j] = dist[i] + d[i][j];
        q.push(PII(dist[j], j));
      } else if (dist[j] > dist[i] + d[i][j]) {
        dist[j] = dist[i] + d[i][j];
        q.push(PII(dist[j], j));
      }
    }
  }
};

// 線分の交差判定
bool isCross(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4) {
  // 並行な場合
  int m = (x2 - x1) * (y4 - y3) - (y2 - y1) * (x4 - x3);
  if (m == 0)
    return false;
  // 媒介変数の値が0より大きく1以下なら交差する、これは問題の状況によって変わるかも。
  double r = (double)((y4 - y3) * (x3 - x1) - (x4 - x3) * (y3 - y1)) / m;
  double s = (double)((y2 - y1) * (x3 - x1) - (x2 - x1) * (y3 - y1)) / m;
  return (0 < r && r <= 1 && 0 < s && s <= 1);
};

// 外積の計算 AB CD の内積を求める
int crossProdct(int ax, int ay, int bx, int by, int cx, int cy, int dx,
                int dy) {
  int abx = bx - ax;
  int aby = by - ay;
  int cdx = dx - cx;
  int cdy = dy - cy;
  return abx * cdy - cdx * aby;
};
double crossProdct(double ax, double ay, double bx, double by, double cx,
                   double cy, double dx, double dy) {
  double abx = bx - ax;
  double aby = by - ay;
  double cdx = dx - cx;
  double cdy = dy - cy;
  return abx * cdy - cdx * aby;
};
double innerProduct(double ax, double ay, double bx, double by, double cx,
                    double cy, double dx, double dy) {
  double abx = bx - ax;
  double aby = by - ay;
  double cdx = dx - cx;
  double cdy = dy - cy;
  return abx * cdx + aby * cdy;
};

// 三角形の内部判定 ABCの中にPがあるか判定
bool inTriangle(int ax, int ay, int bx, int by, int cx, int cy, int px,
                int py) {
  int c1 = crossProdct(ax, ay, bx, by, bx, by, px, py);
  int c2 = crossProdct(bx, by, cx, cy, cx, cy, px, py);
  int c3 = crossProdct(cx, cy, ax, ay, ax, ay, px, py);
  return (c1 > 0 && c2 > 0 && c3 > 0) || (c1 < 0 && c2 < 0 && c3 < 0);
};
bool inTriangle(double ax, double ay, double bx, double by, double cx,
                double cy, double px, double py) {
  double c1 = crossProdct(ax, ay, bx, by, bx, by, px, py);
  double c2 = crossProdct(bx, by, cx, cy, cx, cy, px, py);
  double c3 = crossProdct(cx, cy, ax, ay, ax, ay, px, py);
  return (c1 > 0 && c2 > 0 && c3 > 0) || (c1 < 0 && c2 < 0 && c3 < 0);
};

// 三角形の外心
void circumcenter(double ax, double ay, double bx, double by, double cx,
                  double cy, double res[3]) {
  // AB AC を求める
  double abx = bx - ax;
  double aby = by - ay;
  double acx = cx - ax;
  double acy = cy - ay;
  double m =
      abx * acy - acx * aby; // 分母 m = 0 となるのは3点が一直線になるとき
  double s = (abx * acx + aby * acy - sq(acx) - sq(acy)) / m; // 媒介変数s
  res[0] = abx / 2 + s * aby / 2;
  res[1] = aby / 2 - s * abx / 2;
  // cout << res[0] << " " << res[1] << endl;
  res[2] = sqrt(sqdist(0, 0, res[0], res[1]));
  res[0] += ax;
  res[1] += ay;
};

/**
 * start
 * @author yoshikyoto
 */
int w, h;
string tile[20];
int dist[20][20];
int g[11][11];
int sx[11], sy[11];
int dp[1024][11];
int vy[4] = {-1, 1, 0, 0}, vx[4] = {0, 0, -1, 1};

int dcount = 1;
int p[11];

void dfs(int hist, int curr) {
  for (int next = 1; next < dcount; next++) {
    if (hist & p[next])
      continue; // 既に訪れている
    // 訪れていない
    int next_hist = hist | p[next];
    int cost = dp[hist][curr] + g[curr][next];
    if (cost < dp[next_hist][next] || dp[next_hist][next] == -1) {
      dp[next_hist][next] = cost;
      dfs(next_hist, next);
    }
  }
};

void solve() {
  FOR(i, h) cin >> tile[i];

  // 配列をなめて汚れたタイルの位置を獲得、汚れに番号をつける
  FOR(i, h) FOR(j, w) {
    if (tile[i][j] == '*') {
      sy[dcount] = i;
      sx[dcount] = j;
      tile[i][j] = (char)('0' + dcount); // 汚れに番号を付ける
      dcount++;
    } else if (tile[i][j] == 'o') {
      // 自分の位置
      sy[0] = i;
      sx[0] = j;
      tile[i][j] = '0';
    }
  }
  // グラフの初期化
  FOR(i, dcount) FOR(j, dcount) g[i][j] = -1;
  // FOR(i, h) cout << tile[i] << endl;

  // まずはbfsしてグラフを生成する
  FOR(i, dcount) {
    FOR(k, h) FOR(l, w) dist[k][l] = -1;
    dist[sy[i]][sx[i]] = 0;
    QI yq, xq;
    yq.push(sy[i]);
    xq.push(sx[i]);
    int checked = 1;
    while (checked < dcount && !yq.empty()) {
      int y = yq.front();
      yq.pop();
      int x = xq.front();
      xq.pop();

      // 上下左右を見る
      FOR(j, 4) {
        int ny = y + vy[j], nx = x + vx[j]; // nexty, nextx;
        if (dist[ny][nx] > -1)
          continue; // 既に訪れた場合
        if (ny < 0 || ny > h - 1 || nx < 0 || nx > w - 1)
          continue; // 部屋を出てしまう場合
        int dnum = (int)tile[ny][nx] - '0';
        if (tile[ny][nx] != 'x') {
          // 障害物でない場合
          yq.push(ny);
          xq.push(nx);
          dist[ny][nx] = dist[y][x] + 1;
          // グラフに追加したい場
          if (0 <= dnum && dnum < dcount) {
            g[i][dnum] = dist[ny][nx];
            checked++;
          }
        }
      }
    }
  }

  /*
  FOR(i, dcount){
      FOR(j, dcount){
          cout << g[i][j] << " ";
      }
      cout << endl;
  }
   */

  // 行けないところがあったらダメ
  for (int i = 1; i < dcount; i++)
    if (g[0][i] == -1) {
      cout << -1 << endl;
      return;
    }

  // メモ化再帰
  FOR(i, 1024) FOR(j, 11) dp[i][j] = -1;
  FOR(i, dcount) p[i] = (int)pow(2, i);
  dp[1][0] = 0;
  dfs(1, 0);

  int final = 1;
  for (int i = 1; i < dcount; i++)
    final += p[i];

  int ans = dp[final][1];
  for (int i = 2; i < dcount; i++) {
    ans = min(ans, dp[final][i]);
  }
  cout << ans << endl;
};

int main(int argc, const char *argv[]) {
  begin();
  while (true) {
    cin >> w >> h;
    if (w == 0 && h == 0)
      break;
    dcount = 1;
    solve();
  }
}