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

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

using namespace std;

const int N = 100 + 10;
const long double INF = 1e9;
const long double EPS = 1e-8;
const int OFFSET = 100000;

int sign(long double x) { return x < -EPS ? -1 : x > EPS; }

long double Sqr(long double x) { return x * x; }

struct Point {
  long double x, y;
  Point() {}
  Point(long double x, long double y) : x(x), y(y) {}
  Point operator+(const Point &that) const {
    return Point(x + that.x, y + that.y);
  }
  Point operator-(const Point &that) const {
    return Point(x - that.x, y - that.y);
  }
  Point operator*(const long double &that) const {
    return Point(x * that, y * that);
  }
  Point operator/(const long double &that) const {
    return Point(x / that, y / that);
  }
  void read() { cin >> x >> y; }
  long double dot(const Point &that) const { return x * that.x + y * that.y; }
  long double distTo(const Point &that) const {
    return sqrt(Sqr(x - that.x) + Sqr(y - that.y));
  }
  Point rot90() const { return Point(-y, x); }
};

#define cross(p1, p2, p3)                                                      \\
  ((p2.x - p1.x) * (p3.y - p1.y) - (p3.x - p1.x) * (p2.y - p1.y))
#define crossOp(p1, p2, p3) sign(cross(p1, p2, p3))

int n;
Point bomb;
vector<vector<Point>> polygon;
long double dist[N][N];
bool alive[N][N];
bool in[N][N];

inline bool isIntersect(Point p1, Point p2, Point q1, Point q2) {
  return crossOp(p1, p2, q1) * crossOp(p1, p2, q2) <= 0 &&
         crossOp(q1, q2, p1) * crossOp(q1, q2, p2) < 0;
}

inline Point isSS(Point p1, Point p2, Point q1, Point q2) {
  long double a1 = cross(q1, q2, p1), a2 = -cross(q1, q2, p2);
  return (p1 * a2 + p2 * a1) / (a1 + a2);
}

bool inPolygon(vector<Point> &vec, Point s) {
  int n = vec.size();
  for (int i = 0; i < n; ++i) {
    if (crossOp(vec[i], vec[(i + 1) % n], s) == 0 &&
        sign((vec[i] - s).dot(vec[(i + 1) % n] - s)) <= 0)
      return false;
  }
  int flag = true;
  Point t;
  for (; flag;) {
    t = Point(253514, 999983);
    flag = false;
    for (int i = 0; i < n; ++i) {
      if (crossOp(s, t, vec[i]) == 0) {
        flag = true;
        break;
      }
    }
  }
  int ret = 0;
  for (int i = 0; i < n; ++i) {
    if (isIntersect(s, t, vec[i], vec[(i + 1) % n]))
      ++ret;
  }
  return ret & 1;
}

inline bool inPolygon(Point s) {
  for (int i = 1; i <= n; ++i) {
    if (inPolygon(polygon[i], s)) {
      return true;
    }
  }
  return false;
}

bool isAccess(Point s, Point t) {
  for (int i = 1; i <= n; ++i) {
    for (int j = 0; j < polygon[i].size(); ++j) {
      if (isIntersect(s, t, polygon[i][j],
                      polygon[i][(j + 1) % polygon[i].size()])) {
        return false;
      }
    }
  }
  if (inPolygon((s + t) * 0.5)) {
    return false;
  }
  return true;
}

void solve() {
  bomb.read();
  polygon.clear();
  polygon.push_back(vector<Point>(1, Point(0, 0)));
  for (int i = 0; i < n; ++i) {
    int cnt;
    cin >> cnt;
    vector<Point> vec;
    for (int j = 0; j < cnt; ++j) {
      Point cur;
      cur.read();
      vec.push_back(cur);
    }
    polygon.push_back(vec);
  }
  for (int i = 0; i < polygon.size(); ++i) {
    for (int j = 0; j < polygon[i].size(); ++j) {
      alive[i][j] = false;
    }
    for (int j = 0; j < polygon[i].size(); ++j) {
      if (crossOp(bomb, polygon[i][j],
                  polygon[i][(j + 1) % polygon[i].size()]) > 0)
        alive[i][j] = alive[i][(j + 1) % polygon[i].size()] = true;
    }
  }

  for (int i = 0; i < N; ++i) {
    for (int j = 0; j < N; ++j) {
      dist[i][j] = INF;
      in[i][j] = false;
    }
  }
  dist[0][0] = 0;
  priority_queue<pair<long double, pair<int, int>>> que;
  que.push(make_pair(0, make_pair(0, 0)));

  if (!isAccess(Point(0, 0), bomb)) {
    printf("%.12f\\n", 0.0);
    return;
  }
  long double cut = 1e30;
  for (; que.size();) {
    int a = que.top().second.first;
    int b = que.top().second.second;

    if (a == -1 || alive[a][b]) {
      printf("%.12f\\n", (double)-que.top().first);
      return;
    }
    que.pop();
    if (in[a][b])
      continue;
    in[a][b] = true;

    for (int c = 1; c < polygon.size(); ++c) {
      for (int d = 0; d < polygon[c].size(); ++d) {
        if (dist[c][d] > dist[a][b] + polygon[a][b].distTo(polygon[c][d]) &&
            isAccess(polygon[a][b], polygon[c][d])) {
          dist[c][d] = dist[a][b] + polygon[a][b].distTo(polygon[c][d]);
          que.push(make_pair(-dist[c][d], make_pair(c, d)));
        }
        if (alive[c][d] && isAccess(bomb, polygon[c][d])) {
          Point foot = isSS(bomb, polygon[c][d], polygon[a][b],
                            polygon[a][b] + (polygon[c][d] - bomb).rot90());
          if (foot.distTo(bomb) >= polygon[c][d].distTo(bomb) &&
              isAccess(foot, polygon[a][b])) {
            que.push(make_pair(-dist[a][b] - foot.distTo(polygon[a][b]),
                               make_pair(-1, -1)));
          }
        }
      }
    }
  }
}

int main() {
  ios::sync_with_stdio(false);
  for (; cin >> n && n;) {
    solve();
  }
  return 0;
}

Error: TLE

Fixed submission:

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

using namespace std;

const int N = 100 + 10;
const long double INF = 1e9;
const long double EPS = 1e-8;
const int OFFSET = 100000;

int sign(long double x) { return x < -EPS ? -1 : x > EPS; }

struct Point {
  long double x, y;
  Point() {}
  Point(long double x, long double y) : x(x), y(y) {}
  Point operator+(const Point &that) const {
    return Point(x + that.x, y + that.y);
  }
  Point operator-(const Point &that) const {
    return Point(x - that.x, y - that.y);
  }
  Point operator*(const long double &that) const {
    return Point(x * that, y * that);
  }
  Point operator/(const long double &that) const {
    return Point(x / that, y / that);
  }
  void read() { cin >> x >> y; }
  long double dot(const Point &that) const { return x * that.x + y * that.y; }
  long double distTo(const Point &that) const {
    return hypot(x - that.x, y - that.y);
  }
  Point rot90() const { return Point(-y, x); }
};

#define cross(p1, p2, p3)                                                      \\
  ((p2.x - p1.x) * (p3.y - p1.y) - (p3.x - p1.x) * (p2.y - p1.y))
#define crossOp(p1, p2, p3) sign(cross(p1, p2, p3))

int n;
Point bomb;
vector<vector<Point>> polygon;
long double dist[N][N];
bool alive[N][N];
bool in[N][N];

bool isIntersect(Point p1, Point p2, Point q1, Point q2) {
  return crossOp(p1, p2, q1) * crossOp(p1, p2, q2) <= 0 &&
         crossOp(q1, q2, p1) * crossOp(q1, q2, p2) < 0;
}

Point isSS(Point p1, Point p2, Point q1, Point q2) {
  long double a1 = cross(q1, q2, p1), a2 = -cross(q1, q2, p2);
  return (p1 * a2 + p2 * a1) / (a1 + a2);
}

bool inPolygon(vector<Point> vec, Point s) {
  int n = vec.size();
  for (int i = 0; i < n; ++i) {
    if (crossOp(vec[i], vec[(i + 1) % n], s) == 0 &&
        sign((vec[i] - s).dot(vec[(i + 1) % n] - s)) <= 0)
      return false;
  }
  int flag = true;
  Point t;
  for (; flag;) {
    t = Point(rand() % OFFSET + OFFSET, rand() % OFFSET + OFFSET);
    flag = false;
    for (int i = 0; i < n; ++i) {
      if (crossOp(s, t, vec[i]) == 0) {
        flag = true;
        break;
      }
    }
  }
  int ret = 0;
  for (int i = 0; i < n; ++i) {
    if (isIntersect(s, t, vec[i], vec[(i + 1) % n]))
      ++ret;
  }
  return ret & 1;
}

bool inPolygon(Point s) {
  for (int i = 1; i <= n; ++i) {
    if (inPolygon(polygon[i], s)) {
      return true;
    }
  }
  return false;
}

bool isAccess(Point s, Point t) {
  if (inPolygon((s + t) * 0.5)) {
    return false;
  }
  for (int i = 1; i <= n; ++i) {
    for (int j = 0; j < polygon[i].size(); ++j) {
      if (isIntersect(s, t, polygon[i][j],
                      polygon[i][(j + 1) % polygon[i].size()])) {
        return false;
      }
    }
  }
  return true;
}

void solve() {
  bomb.read();
  polygon.clear();
  polygon.push_back(vector<Point>(1, Point(0, 0)));
  for (int i = 0; i < n; ++i) {
    int cnt;
    cin >> cnt;
    vector<Point> vec;
    for (int j = 0; j < cnt; ++j) {
      Point cur;
      cur.read();
      vec.push_back(cur);
    }
    polygon.push_back(vec);
  }
  for (int i = 0; i < polygon.size(); ++i) {
    for (int j = 0; j < polygon[i].size(); ++j) {
      alive[i][j] = false;
    }
    for (int j = 0; j < polygon[i].size(); ++j) {
      if (crossOp(bomb, polygon[i][j],
                  polygon[i][(j + 1) % polygon[i].size()]) > 0)
        alive[i][j] = alive[i][(j + 1) % polygon[i].size()] = true;
    }
  }

  for (int i = 0; i < N; ++i) {
    for (int j = 0; j < N; ++j) {
      dist[i][j] = INF;
      in[i][j] = false;
    }
  }
  dist[0][0] = 0;
  priority_queue<pair<long double, pair<int, int>>> que;
  que.push(make_pair(0, make_pair(0, 0)));

  if (!isAccess(Point(0, 0), bomb)) {
    printf("%.12f\\n", 0.0);
    return;
  }

  for (; que.size();) {
    int a = que.top().second.first;
    int b = que.top().second.second;

    if (a == -1 || alive[a][b]) {
      printf("%.12f\\n", (double)-que.top().first);
      return;
    }
    que.pop();
    if (in[a][b])
      continue;
    in[a][b] = true;

    for (int c = 1; c < polygon.size(); ++c) {
      for (int d = 0; d < polygon[c].size(); ++d) {
        if (isAccess(polygon[a][b], polygon[c][d]) &&
            dist[c][d] > dist[a][b] + polygon[a][b].distTo(polygon[c][d])) {
          dist[c][d] = dist[a][b] + polygon[a][b].distTo(polygon[c][d]);
          que.push(make_pair(-dist[c][d], make_pair(c, d)));
        }
        if (alive[c][d] && isAccess(bomb, polygon[c][d])) {
          Point foot = isSS(bomb, polygon[c][d], polygon[a][b],
                            polygon[a][b] + (polygon[c][d] - bomb).rot90());
          if (foot.distTo(bomb) >= polygon[c][d].distTo(bomb) &&
              isAccess(foot, polygon[a][b])) {
            que.push(make_pair(-dist[a][b] - foot.distTo(polygon[a][b]),
                               make_pair(-1, -1)));
          }
        }
      }
    }
  }
}

int main() {
  ios::sync_with_stdio(false);
  for (; cin >> n && n;) {
    solve();
  }
  return 0;
}