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

#include <algorithm>
#include <cmath>
#include <cstdio>
#include <queue>

#define rep(i, n) for (int i = 0; i < (n); i++)

using namespace std;

const double INF = 1e77;
const double PI = acos(-1);

struct point {
  int r, i;
  bool operator==(const point &p) const { return r == p.r && i == p.i; }
};

struct edge {
  int v;
  double cost;
};

int main() {
  for (int n, m; scanf("%d%d", &n, &m), n || m;) {
    const double COST = 2 * sin(PI / n); // 正 n 角形の一辺の長さ

    point s, t;
    scanf("%d%d%d%d", &s.r, &s.i, &t.r, &t.i);
    s.i--;
    t.i--;
    point bad[100][2];
    rep(i, m) rep(j, 2) scanf("%d%d", &bad[i][j].r, &bad[i][j].i),
        bad[i][j].i--;

    vector<int> R; // 候補となる頂点の r の値
    R.push_back(1);
    R.push_back(s.r);
    R.push_back(t.r);
    rep(i, m) rep(j, 2) {
      R.push_back(bad[i][j].r);
      R.push_back(bad[i][j].r + 1);
      R.push_back(max(bad[i][j].r - 1, 1));
    }
    sort(R.begin(), R.end());
    R.erase(unique(R.begin(), R.end()), R.end());

    int N = n * R.size();
    static vector<edge> G[60300];
    rep(u, N) G[u].clear();
    rep(i, R.size()) {
      int r = R[i];
      rep(j, n) {
        // 左
        bool ok = true;
        rep(k, m) {
          if (bad[k][0] == (point){r, j} &&
                  bad[k][1] == (point){r, (j - 1 + n) % n} ||
              bad[k][1] == (point){r, j} &&
                  bad[k][0] == (point){r, (j - 1 + n) % n})
            ok = false;
        }
        if (ok) {
          int u = n * i + j, v = n * i + (j - 1 + n) % n;
          G[u].push_back((edge){v, r * COST});
          G[v].push_back((edge){u, r * COST});
        }

        // 上
        if (i + 1 < R.size()) {
          ok = true;
          int r2 = R[i + 1];
          rep(k, m) {
            if (bad[k][0] == (point){r, j} && bad[k][1] == (point){r2, j} ||
                bad[k][1] == (point){r, j} && bad[k][0] == (point){r2, j})
              ok = false;
          }
          if (ok) {
            int u = n * i + j, v = n * (i + 1) + j;
            G[u].push_back((edge){v, r2 - r});
            G[v].push_back((edge){u, r2 - r});
          }
        }
      }
    }

    // Dijkstra
    int s_id = n * (find(R.begin(), R.end(), s.r) - R.begin()) + s.i;
    int t_id = n * (find(R.begin(), R.end(), t.r) - R.begin()) + t.i;
    static double d[60300];
    rep(u, N) { d[u] = (u == s_id ? 0 : INF); }
    priority_queue<pair<double, int>> Q;
    Q.push(make_pair(0, s_id));
    while (!Q.empty()) {
      double d_now = -Q.top().first;
      int u = Q.top().second;
      Q.pop();

      if (d_now > d[u])
        continue;

      rep(i, G[u].size()) {
        edge e = G[u][i];
        if (d[e.v] > d[u] + e.cost) {
          d[e.v] = d[u] + e.cost;
          Q.push(make_pair(-d[e.v], e.v));
        }
      }
    }

    printf("%.9f\\n", d[t_id]);
  }

  return 0;
}

Error: TLE

Fixed submission:

#include <cmath>
#include <cstdio>
#include <vector>

#define rep(i, n) for (int i = 0; i < (n); i++)

using namespace std;

const double INF = 1e77;
const double PI = acos(-1);

struct point {
  int r, i;
};

int main() {
  for (int n, m; scanf("%d%d", &n, &m), n || m;) {
    point s, t;
    scanf("%d%d%d%d", &s.r, &s.i, &t.r, &t.i);
    point bad[100][2];
    rep(i, m) rep(j, 2) {
      scanf("%d%d", &bad[i][j].r, &bad[i][j].i);
      if (bad[i][0].i == 1 && bad[i][1].i == n)
        bad[i][0].i += n;
      if (bad[i][0].i == n && bad[i][1].i == 1)
        bad[i][1].i += n;
    }

    vector<point> V;
    V.push_back(s);
    V.push_back(t);
    rep(i, m) rep(j, 2) {
      V.push_back(bad[i][j]);
      if (bad[i][j].r > 1) {
        V.push_back((point){bad[i][j].r - 1, bad[i][j].i});
      }
      V.push_back((point){bad[i][j].r + 1, bad[i][j].i});
      V.push_back((point){bad[i][j].r, (bad[i][j].i + 1) % n});
      V.push_back((point){bad[i][j].r, (bad[i][j].i - 1 + n) % n});
    }

    int N = V.size();
    static double d[1002][1002];
    rep(u, N) rep(v, N) {
      d[u][v] = INF;

      // a から b へ最短経路で移動できるかどうかを調べる
      point a = V[u], b = V[v];
      int r_min = min(a.r, b.r), r_max = max(a.r, b.r);
      int i_min = min(a.i, b.i), i_max = max(a.i, b.i);
      if (i_min == 1 && i_max == n)
        i_min = n, i_max = n + 1;

      // r 方向の移動
      if (a.r != b.r) {
        bool ok = true;
        if (a.r > b.r)
          swap(a, b);
        rep(i, m) if (bad[i][0].i == bad[i][1].i) {
          if (bad[i][0].i == b.i && r_min <= bad[i][0].r &&
              bad[i][0].r <= r_max && r_min <= bad[i][1].r &&
              bad[i][1].r <= r_max)
            ok = false;
        }
        if (!ok)
          continue;
      }

      // i 方向の移動
      if (a.i != b.i) {
        // i が増える向きに回る
        bool ok1 = false;
        if (i_max - i_min <= (i_min - i_max + n) % n) {
          ok1 = true;
          rep(i, m) if (bad[i][0].r == bad[i][1].r) {
            if (bad[i][0].r == r_min && i_min <= bad[i][0].i &&
                bad[i][0].i <= i_max && i_min <= bad[i][1].i &&
                bad[i][1].i <= i_max)
              ok1 = false;
          }
        }
        // i が減る向きに回る
        bool ok2 = false;
        if ((i_min - i_max + n) % n <= i_max - i_min) {
          ok2 = true;
          rep(i, m) if (bad[i][0].r == bad[i][1].r) {
            if (bad[i][0].r == r_min &&
                (bad[i][0].i <= i_min || i_max <= bad[i][0].i) &&
                (bad[i][1].i <= i_min || i_max <= bad[i][1].i))
              ok2 = false;
          }
        }
        if (!ok1 && !ok2)
          continue;
      }

      d[u][v] = (i_max - i_min) * r_min * sqrt(2 - 2 * cos(2 * PI / n)) +
                (r_max - r_min);
    }

    rep(w, N) rep(u, N) rep(v, N) d[u][v] = min(d[u][v], d[u][w] + d[w][v]);

    printf("%.9f\\n", d[0][1]);
  }

  return 0;
}