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

#include <cassert>
#include <cmath>
#include <complex>
#include <cstdio>
#include <fstream>
#include <functional>
#include <iostream>
#include <queue>
#include <set>
#include <stack>
#include <vector>

enum ENUM_CCW {
  FRONT = 0x01,
  RIGHT = 0x02,
  BACK = 0x04,
  LEFT = 0x08,
  OVER = 0x10
};

#define sc second
#define fr first

using namespace std;

typedef double elem;
typedef complex<elem> point, vec;
typedef pair<point, point> line, hline, seg, pp;

const double infty = 1e40;
const double eps = 1.0e-8;
const double pi = acos(-1.0);

inline bool eq(elem a, elem b) { return abs(a - b) < eps; }
inline bool far(const point &a, const point &b) { return abs(b - a) > 0; }
inline bool near(const point &a, const point &b) { return abs(b - a) <= 0; }
inline elem dot(const vec &a, const vec &b) {
  return (a.real() * b.real() + a.imag() * b.imag());
}
inline elem cross(const vec &a, const vec &b) {
  return (a.real() * b.imag() - a.imag() * b.real());
}
inline vec uvec(const vec &a) { return a / abs(a); }
inline vec nmr(const vec &a) { return a * vec(0, -1); }
inline vec unmr(const vec &a) { return uvec(nmr(a)); }
inline elem dist_l(const line &l, const point &x) {
  return abs(cross(l.sc - l.fr, x - l.fr)) / abs(l.sc - l.fr);
}
inline int ccw(const point &a, point b, point x) {
  b -= a;
  x -= a;
  if (eq(cross(b, x), 0.0) && dot(b, x) < 0)
    return BACK;
  if (eq(cross(b, x), 0.0) && abs(b) < abs(x))
    return FRONT;
  if (eq(cross(b, x), 0.0))
    return OVER;
  if (cross(b, x) > 0)
    return LEFT;
  if (cross(b, x) < 0)
    return RIGHT;
}
inline bool intersectedSS(const seg &a, const seg &b) {
  int cwaf = ccw(a.fr, a.sc, b.fr);
  int cwbf = ccw(b.fr, b.sc, a.fr);
  int cwas = ccw(a.fr, a.sc, b.sc);
  int cwbs = ccw(b.fr, b.sc, a.sc);
  if (cwaf == OVER || cwas == OVER || cwbf == OVER || cwbs == OVER)
    return true;
  return (cwaf | cwas) == (LEFT | RIGHT) && (cwbf | cwbs) == (LEFT | RIGHT);
}
inline bool intersectedLL(const line &a, const line &b) {
  return !eq(cross(a.sc - a.fr, b.sc - b.fr), 0.0);
}
inline point intersectionSS(const seg &a, const seg &b) {
  elem d1 = dist_l(b, a.fr);
  elem d2 = dist_l(b, a.sc);
  return a.fr + (d1 / (d1 + d2)) * (a.sc - a.fr);
}
inline point intersectionLL(const line &a, const line &b) {
  vec va = a.sc - a.fr;
  vec vb = b.sc - b.fr;
  return a.fr + va * (cross(vb, b.fr - a.fr) / cross(vb, va));
}
inline bool intersectionLL(const line &a, const line &b, point &ret) {
  return intersectedLL(a, b) ? ret = intersectionLL(a, b), true : false;
}
inline bool intersectionLH(const line &a, const hline &b, point &ret) {
  point tmp;
  return intersectionLL(a, b, tmp)
             ? (ccw(b.fr, b.sc, tmp) & (OVER | FRONT) ? ret = tmp, true : false)
             : false;
}
inline bool intersectionLS(const line &l, const seg &s, point &ret) {
  point tmp;
  return intersectionLL(l, s, tmp)
             ? (ccw(s.fr, s.sc, tmp) & OVER ? ret = tmp, true : false)
             : false;
}
inline bool intersectionHH(const hline &a, const hline &b, point &ret) {
  point tmp;
  return intersectionLL(a, b, tmp) ? (ccw(a.fr, a.sc, tmp) & (OVER | FRONT) &&
                                          ccw(b.fr, b.sc, tmp) & (OVER | FRONT)
                                      ? ret = tmp,
                                      true : false)
                                   : false;
}
inline bool intersectionHS(const hline &a, const seg &s, point &ret) {
  point tmp;
  return intersectionLS(a, s, tmp)
             ? (ccw(a.fr, a.sc, tmp) & (OVER | FRONT) ? ret = tmp, true : false)
             : false;
}
inline bool intersectionSS(const seg &a, const seg &b, point &ret) {
  return intersectedSS(a, b) ? ret = intersectionSS(a, b), true : false;
}

bool inSimple(const point &x, int n, point p[]) {
  int cnt = 0;
  for (int i = 0; i < n; ++i) {
    point a = p[i] - x, b = p[(i + 1) % n] - x;
    if (b.imag() > a.imag())
      swap(a, b);
    int cw = ccw(a, b, point(0, 0));
    if (cw == LEFT && 0 <= a.imag() && b.imag() < 0)
      ++cnt;
    if (cw == OVER)
      return false;
  }
  if (cnt & 1)
    return true;
  else
    return false;
}

struct State {
  int n;
  elem cost;
  State(int n, elem cost) : n(n), cost(cost) {}
  State() {}
  bool operator<(const State &t) const { return cost > t.cost; }
};

#define MAXN 512

int N;
point B[MAXN][128];
int nB[MAXN];
int nG;
point G[MAXN];
int GSafe[MAXN];
int nGoal;
point Goal[2 * MAXN];

bool isConnected(const point &a, const point &b) {
  point x = (a + b) / (elem)2.0;
  for (int i = 0; i < N; ++i) {
    //    if(inSimple(x,nB[i],B[i]))return false;
    int cnt = 0;
    for (int j = 0; j < nB[i]; ++j) {
      point p = B[i][j];
      point np = B[i][(1 + j) % nB[i]];
      point tmp;
      if (intersectionSS(seg(a, b), seg(p, np), tmp)) {
        if (far(tmp, a) && far(tmp, b))
          return false;
      }
      point a = B[i][j] - x, b = B[i][(j + 1) % nB[i]] - x;
      if (b.imag() > a.imag())
        swap(a, b);
      int cw = ccw(a, b, point(0, 0));
      if (cw == LEFT && 0 <= a.imag() && b.imag() < 0)
        ++cnt;
      if (cw == OVER) {
        cnt = 0;
        break;
      }
    }
    if (cnt & 1)
      return false;
  }
  return true;
}

elem solve() {
  elem ret = infty;
  elem A[nG];
  bool visited[nG];
  bool adj[nG][nG];
  priority_queue<State> Q;
  State init(0, 0.0);
  Q.push(init);

  for (int i = 0; i < nG; ++i) {
    visited[i] = false;
    A[i] = infty;
    for (int j = 0; j < nG; ++j) {
      adj[i][j] = false;
    }
  }

  A[0] = 0.0;
  while (!Q.empty()) {
    State nst = Q.top();
    Q.pop();
    if (visited[nst.n])
      continue;
    visited[nst.n] = true;
    point np = G[nst.n];
    if (GSafe[nst.n]) {
      ret = min(ret, nst.cost);
      break;
    }

    for (int i = 0; i < nGoal; ++i) {
      if (isConnected(np, Goal[i])) {
        ret = min(ret, nst.cost + abs(Goal[i] - np));
      }
    }

    for (int i = 1; i < nG; ++i) {
      if (nst.n == i)
        continue;
    retry:;
      if (adj[nst.n][i]) {
        elem nxcost = nst.cost + abs(G[i] - np);
        if (A[i] > nxcost) {
          A[i] = nxcost;
          if (!visited[i]) {
            Q.push(State(i, nxcost));
          }
        }
      } else {
        if (isConnected(np, G[i])) {
          adj[nst.n][i] = adj[i][nst.n] = true;
          goto retry;
        }
      }
    }
  }
  return ret;
}

bool eqseg(seg a, seg b) {
  return (near(a.fr, b.fr) && near(a.sc, b.sc)) ||
         (near(a.fr, b.sc) && near(a.sc, b.fr));
}

int main() {
  point p(0, 0);
  point s;

  while (true) {
    // input
    cin >> N;
    if (N == 0)
      break;
    elem bx, by;
    cin >> bx >> by;
    point bomb(bx, by);
    point alice(0, 0);

    for (int i = 0; i < N; ++i) {
      int m;
      cin >> m;
      nB[i] = m;
      for (int j = 0; j < m; ++j) {
        elem x, y;
        cin >> x >> y;
        B[i][j] = point(x, y);
      }
    }

    for (int i = 0; i < N; ++i) {
      for (int j = 0; j < nB[i]; ++j) {
        point p = B[i][j];
        point nexp = B[i][(j + 1) % nB[i]];
      }
    }

    // graph points
    nG = 1;
    nGoal = 0;
    G[0] = alice;
    GSafe[0] = 0;
    for (int i = 0; i < N; ++i) {
      for (int j = 0; j < nB[i]; ++j) {

        point p = B[i][j];
        // vertex
        G[nG] = p;
        {
          // is safe vertex ?
          bool safe = false;
          point prep = B[i][(j - 1 + nB[i]) % nB[i]];
          point nexp = B[i][(j + 1) % nB[i]];
          point cp = (p + prep) / (elem)2.0;
          point cx = (p + nexp) / (elem)2.0;
          hline lcp(bomb, cp);
          hline lcx(bomb, cx);

          point tmp;

          // there is a segment that guards alice from bomb
          if (intersectionSS(seg(bomb, alice), seg(p, prep), tmp) &&
              far(tmp, bomb) && far(tmp, alice)) {
            GSafe[0] = 1;
          }

          for (int k = 0; k < N; ++k) {
            for (int m = 0; m < nB[k]; ++m) {
              seg s(B[k][m], B[k][(m + 1) % nB[k]]);
              if (eqseg(lcp, s))
                continue;
              point is;
              if (intersectionSS(lcp, s, is) && far(is, cp) &&
                  abs(is - bomb) < abs(cp - bomb)) {
                if (ccw(p, prep, alice) == OVER) {
                  GSafe[0] = 1;
                }
                safe = true;
              }
              if (intersectionSS(lcx, s, is) && far(is, cx) &&
                  abs(is - bomb) < abs(cx - bomb)) {
                if (ccw(p, nexp, alice) == OVER) {
                  GSafe[0] = 1;
                }
                safe = true;
              }
            }
            if (safe)
              break;
          }
          if (safe) {
            GSafe[nG] = 1;
          } else {
            GSafe[nG] = 0;
          }
        }
        ++nG;

        // vertical line
        if (far(bomb, p)) {
          hline l(bomb, p);
          line al(alice, alice + unmr(bomb - p));
          point is;
          if (intersectionLH(al, l, is)) {
            bool skip = false;
            for (int k = 0; k < N; ++k) {
              if (inSimple(is, nB[k], B[k]))
                skip = true;
              for (int m = 0; m < nB[k]; ++m) {
                if (near(is, B[k][m]) || near(is, alice)) {
                  skip = true;
                }
              }
            }
            if (!skip && abs(is - bomb) > abs(p - bomb)) {
              Goal[nGoal] = is;
              nGoal++;
            }
          }

          // half line and polygon
          for (int k = 0; k < N; ++k) {
            for (int m = 0; m < nB[k]; ++m) {
              seg s(B[k][m], B[k][(m + 1) % nB[k]]);
              if (intersectionHS(l, s, is)) {
                if (far(is, p) && far(is, s.first) && far(is, s.second) &&
                    abs(is - bomb) > abs(p - bomb)) {
                  Goal[nGoal] = is;
                  nGoal++;
                }
              }
            }
          }
        }
      }
    }

    printf("%.12lf\\n", solve());
  }
  return 0;
}

Error: TLE

Fixed submission:

#include <cassert>
#include <cmath>
#include <complex>
#include <cstdio>
#include <fstream>
#include <functional>
#include <iostream>
#include <queue>
#include <set>
#include <stack>
#include <vector>

enum ENUM_CCW {
  FRONT = 0x01,
  RIGHT = 0x02,
  BACK = 0x04,
  LEFT = 0x08,
  OVER = 0x10
};

#define sc second
#define fr first

using namespace std;

typedef long double elem;
typedef complex<elem> point, vec;
typedef pair<point, point> line, hline, seg, pp;

const double infty = 1e40;
const double eps = 1.0e-8;
const double pi = acos(-1.0);
// ofstream vis("vis.txt");

inline bool eq(elem a, elem b) { return abs(a - b) < eps; }
inline bool far(const point &a, const point &b) { return abs(b - a) > 0; }
inline bool near(const point &a, const point &b) { return abs(b - a) <= 0; }
inline elem dot(const vec &a, const vec &b) {
  return (a.real() * b.real() + a.imag() * b.imag());
}
inline elem cross(const vec &a, const vec &b) {
  return (a.real() * b.imag() - a.imag() * b.real());
}
inline vec uvec(const vec &a) { return a / abs(a); }
inline vec nmr(const vec &a) { return a * vec(0, -1); }
inline vec unmr(const vec &a) { return uvec(nmr(a)); }
inline elem dist_l(const line &l, const point &x) {
  return abs(cross(l.sc - l.fr, x - l.fr)) / abs(l.sc - l.fr);
}
inline int ccw(const point &a, point b, point x) {
  b -= a;
  x -= a;
  if (eq(cross(b, x), 0.0) && dot(b, x) < 0)
    return BACK;
  if (eq(cross(b, x), 0.0) && abs(b) < abs(x))
    return FRONT;
  if (eq(cross(b, x), 0.0))
    return OVER;
  if (cross(b, x) > 0)
    return LEFT;
  if (cross(b, x) < 0)
    return RIGHT;
}
inline bool intersectedSS(const seg &a, const seg &b) {
  int cwaf = ccw(a.fr, a.sc, b.fr);
  int cwbf = ccw(b.fr, b.sc, a.fr);
  int cwas = ccw(a.fr, a.sc, b.sc);
  int cwbs = ccw(b.fr, b.sc, a.sc);
  if (cwaf == OVER || cwas == OVER || cwbf == OVER || cwbs == OVER)
    return true;
  return (cwaf | cwas) == (LEFT | RIGHT) && (cwbf | cwbs) == (LEFT | RIGHT);
}
bool intersectedLL(const line &a, const line &b) {
  return !eq(cross(a.sc - a.fr, b.sc - b.fr), 0.0);
}
point intersectionSS(const seg &a, const seg &b) {
  elem d1 = dist_l(b, a.fr);
  elem d2 = dist_l(b, a.sc);
  return a.fr + (d1 / (d1 + d2)) * (a.sc - a.fr);
}
point intersectionLL(const line &a, const line &b) {
  vec va = a.sc - a.fr;
  vec vb = b.sc - b.fr;
  return a.fr + va * (cross(vb, b.fr - a.fr) / cross(vb, va));
}

bool intersectionLL(const line &a, const line &b, point &ret) {
  return intersectedLL(a, b) ? ret = intersectionLL(a, b), true : false;
}
bool intersectionLH(const line &a, const hline &b, point &ret) {
  point tmp;
  return intersectionLL(a, b, tmp)
             ? (ccw(b.fr, b.sc, tmp) & (OVER | FRONT) ? ret = tmp, true : false)
             : false;
}
bool intersectionLS(const line &l, const seg &s, point &ret) {
  point tmp;
  return intersectionLL(l, s, tmp)
             ? (ccw(s.fr, s.sc, tmp) & OVER ? ret = tmp, true : false)
             : false;
}
bool intersectionHH(const hline &a, const hline &b, point &ret) {
  point tmp;
  return intersectionLL(a, b, tmp) ? (ccw(a.fr, a.sc, tmp) & (OVER | FRONT) &&
                                          ccw(b.fr, b.sc, tmp) & (OVER | FRONT)
                                      ? ret = tmp,
                                      true : false)
                                   : false;
}
bool intersectionHS(const hline &a, const seg &s, point &ret) {
  point tmp;
  return intersectionLS(a, s, tmp)
             ? (ccw(a.fr, a.sc, tmp) & (OVER | FRONT) ? ret = tmp, true : false)
             : false;
}
inline bool intersectionSS(const seg &a, const seg &b, point &ret) {
  return intersectedSS(a, b) ? ret = intersectionSS(a, b), true : false;
}

// P½p`Ìàï»è(«EüÜÜÈ¢)
bool inSimple(const point &x, int n, point p[]) {
  int cnt = 0;
  for (int i = 0; i < n; ++i) {
    point a = p[i] - x, b = p[(i + 1) % n] - x;
    if (b.imag() > a.imag())
      swap(a, b);
    int cw = ccw(a, b, point(0, 0));
    if (cw == LEFT && 0 <= a.imag() && b.imag() < 0)
      ++cnt;
    if (cw == OVER)
      return false;
  }
  if (cnt & 1)
    return true;
  else
    return false;
}

struct State {
  int n;
  elem cost;
  State(int n, elem cost) : n(n), cost(cost) {}
  State() {}
  bool operator<(const State &t) const { return cost > t.cost; }
};

#define MAXN 512

int N;
point B[MAXN][128];
int nB[MAXN];
int nG;
point G[MAXN];
int GSafe[MAXN];
int nGoal;
point Goal[2 * MAXN];
int conv[MAXN][MAXN];
bool Unconnected[MAXN][MAXN]; // when there is no segments between i and j where
                              // i and j is one of segments of buildings.

bool isConnected(const point &a, const point &b) {
  point x = (a + b) / (elem)2.0;
  for (int i = 0; i < N; ++i) {
    if (inSimple(x, nB[i], B[i]))
      return false;
    for (int j = 0; j < nB[i]; ++j) {
      point p = B[i][j];
      point np = B[i][(1 + j) % nB[i]];
      point tmp;
      if (intersectionSS(seg(a, b), seg(p, np), tmp)) {
        if (far(tmp, a) && far(tmp, b))
          return false;
      }
    }
  }
  return true;
}

elem solve() {
  elem ret = infty;
  elem A[nG];
  bool visited[nG];
  bool adj[nG][nG];
  priority_queue<State> Q;
  State init(0, 0.0);
  Q.push(init);

  for (int i = 0; i < nG; ++i) {
    visited[i] = false;
    A[i] = infty;
    for (int j = 0; j < nG; ++j) {
      adj[i][j] = false;
    }
  }

  elem remain[nG];
  for (int i = 0; i < nG; ++i) {
    elem rem = infty;
    for (int j = 0; j < nG; ++j) {
      if (GSafe[j]) {
        rem = min(rem, abs(G[j] - G[i]));
      }
    }
    for (int j = 0; j < nGoal; ++j) {
      rem = min(rem, abs(Goal[j] - G[i]));
    }
    remain[i] = rem;
  }

  A[0] = 0.0;
  while (!Q.empty()) {
    State nst = Q.top();
    Q.pop();
    if (visited[nst.n])
      continue;
    visited[nst.n] = true;
    point np = G[nst.n];
    if (GSafe[nst.n]) {
      ret = min(ret, nst.cost);
      break;
    }
    if (nst.cost + remain[nst.n] >= ret)
      continue;

    for (int i = 0; i < nGoal; ++i) {
      if (isConnected(np, Goal[i])) {
        ret = min(ret, nst.cost + abs(Goal[i] - np));
      }
    }

    for (int i = 1; i < nG; ++i) {
      if (nst.n == i)
        continue;
    retry:;
      if (adj[nst.n][i]) {
        elem nxcost = nst.cost + abs(G[i] - np);
        if (A[i] > nxcost) {
          A[i] = nxcost;
          if (!visited[i]) {
            Q.push(State(i, nxcost));
          }
        }
      } else {
        if (isConnected(np, G[i])) {
          adj[nst.n][i] = adj[i][nst.n] = true;
          goto retry;
        }
      }
    }
  }

  int min_i = -1;
  for (int i = 0; i < nG; ++i) {
    if (GSafe[i]) {
      if (ret > A[i]) {
        ret = A[i];
        min_i = i;
      }
    }
  }
  return ret;
}

bool eqseg(seg a, seg b) {
  return (near(a.fr, b.fr) && near(a.sc, b.sc)) ||
         (near(a.fr, b.sc) && near(a.sc, b.fr));
}

int main() {
  point p(0, 0);
  point s;

  while (true) {
    // input
    cin >> N;
    if (N == 0)
      break;
    elem bx, by;
    cin >> bx >> by;
    point bomb(bx, by);
    point alice(0, 0);

    for (int i = 0; i < N; ++i) {
      int m;
      cin >> m;
      nB[i] = m;
      for (int j = 0; j < m; ++j) {
        elem x, y;
        cin >> x >> y;
        B[i][j] = point(x, y);
      }
    }

    for (int i = 0; i < N; ++i) {
      for (int j = 0; j < nB[i]; ++j) {
        point p = B[i][j];
        point nexp = B[i][(j + 1) % nB[i]];
      }
    }

    // graph points
    nG = 1;
    nGoal = 0;
    G[0] = alice;
    GSafe[0] = 0;
    for (int i = 0; i < N; ++i) {
      for (int j = 0; j < nB[i]; ++j) {

        point p = B[i][j];
        // vertex
        G[nG] = p;
        conv[i][j] = nG;
        {
          // is safe vertex ?
          bool safe = false;
          point prep = B[i][(j - 1 + nB[i]) % nB[i]];
          point nexp = B[i][(j + 1) % nB[i]];
          point cp = (p + prep) / (elem)2.0;
          point cx = (p + nexp) / (elem)2.0;
          hline lcp(bomb, cp);
          hline lcx(bomb, cx);

          point tmp;

          // there is a segment that guards alice from bomb
          if (intersectionSS(seg(bomb, alice), seg(p, prep), tmp) &&
              far(tmp, bomb) && far(tmp, alice)) {
            GSafe[0] = 1;
          }

          for (int k = 0; k < N; ++k) {
            for (int m = 0; m < nB[k]; ++m) {
              seg s(B[k][m], B[k][(m + 1) % nB[k]]);
              if (eqseg(lcp, s))
                continue;
              point is;
              if (intersectionSS(lcp, s, is) && far(is, cp) &&
                  abs(is - bomb) < abs(cp - bomb)) {
                if (ccw(p, prep, alice) == OVER) {
                  GSafe[0] = 1;
                }
                safe = true;
              }
              if (intersectionSS(lcx, s, is) && far(is, cx) &&
                  abs(is - bomb) < abs(cx - bomb)) {
                if (ccw(p, nexp, alice) == OVER) {
                  GSafe[0] = 1;
                }
                safe = true;
              }
            }
            if (safe)
              break;
          }
          if (safe) {
            GSafe[nG] = 1;
          } else {
            GSafe[nG] = 0;
          }
        }
        ++nG;

        // vertical line
        if (far(bomb, p)) {
          hline l(bomb, p);
          line al(alice, alice + unmr(bomb - p));
          point is;
          if (intersectionLH(al, l, is)) {
            bool skip = false;
            // vis <<
            // "line("<<alice.real()<<","<<alice.imag()<<","<<is.real()<<","<<is.imag()<<");"<<endl;
            for (int k = 0; k < N; ++k) {
              if (inSimple(is, nB[k], B[k]))
                skip = true;
              for (int m = 0; m < nB[k]; ++m) {
                if (near(is, B[k][m]) || near(is, alice)) {
                  skip = true;
                }
              }
            }
            if (!skip && abs(is - bomb) > abs(p - bomb)) {
              Goal[nGoal] = is;
              nGoal++;
            }
          }

          // half line and polygon
          for (int k = 0; k < N; ++k) {
            for (int m = 0; m < nB[k]; ++m) {
              seg s(B[k][m], B[k][(m + 1) % nB[k]]);
              if (intersectionHS(l, s, is)) {
                if (far(is, p) && far(is, s.first) && far(is, s.second) &&
                    abs(is - bomb) > abs(p - bomb)) {
                  Goal[nGoal] = is;
                  nGoal++;
                }
              }
            }
          }
        }
      }
    }

    printf("%.12Lf\\n", solve());
  }
  return 0;
}