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

#include <algorithm>
#include <array>
#include <cmath>
#include <complex>
#include <iomanip>
#include <iostream>
#include <vector>
using namespace std;
const double EPS = 1e-8;
const double INF = 1e12;
#define EQ(n, m) (abs((n) - (m)) < EPS)
#define X real()
#define Y imag()

typedef complex<double> P;
typedef vector<P> VP;
struct L : array<P, 2> {
  L(const P &a, const P &b) {
    at(0) = a;
    at(1) = b;
  }
  L() {}
};
struct C {
  P p;
  double r;
  C(const P &p, const double &r) : p(p), r(r) {}
  C() {}
};
namespace std {
bool operator<(const P &a, const P &b) {
  return (a.X != b.X) ? a.X < b.X : a.Y < b.Y;
}
bool operator==(const P &a, const P &b) { return abs(a - b) < EPS; }
} // namespace std

double dot(P a, P b) { return (conj(a) * b).X; }
double cross(P a, P b) { return (conj(a) * b).Y; }
int ccw(P a, P b, P c) {
  b -= a;
  c -= a;
  if (cross(b, c) > EPS)
    return +1; // ccw
  if (cross(b, c) < -EPS)
    return -1; // cw
  if (dot(b, c) < -EPS)
    return +2; // c-a-b
  if (abs(c) - abs(b) > EPS)
    return -2; // a-b-c
  return 0;    // a-c-b
}
P unit(const P &p) { return p / abs(p); }

double distanceLP(const L &l, const P &p) {
  return abs(cross(l[1] - l[0], p - l[0])) / abs(l[1] - l[0]);
}
double distanceSP(const L &s, const P &p) {
  if (dot(s[1] - s[0], p - s[0]) < EPS)
    return abs(p - s[0]);
  if (dot(s[0] - s[1], p - s[1]) < EPS)
    return abs(p - s[1]);
  return distanceLP(s, p);
}
bool intersectSP(const L &s, const P &p) {
  return abs(cross(s[0] - p, s[1] - p)) < EPS && dot(s[0] - p, s[1] - p) < EPS;
}
bool intersectSS(const L &a, const L &b) {
  return (ccw(a[0], a[1], b[0]) * ccw(a[0], a[1], b[1]) <= 0) &&
         (ccw(b[0], b[1], a[0]) * ccw(b[0], b[1], a[1]) <= 0);
}

P projection(const L &l, const P &p) {
  double t = dot(p - l[0], l[0] - l[1]) / norm(l[0] - l[1]);
  return l[0] + t * (l[0] - l[1]);
}
P reflection(const L &l, const P &p) {
  return p + 2.0 * (projection(l, p) - p);
}
bool isParallel(const P &a, const P &b) { return abs(cross(a, b)) < EPS; }
bool isParallel(const L &a, const L &b) {
  return isParallel(a[1] - a[0], b[1] - b[0]);
}

P crosspointLL(const L &l, const L &m) {
  double A = cross(l[1] - l[0], m[1] - m[0]);
  double B = cross(l[1] - l[0], l[1] - m[0]);
  return m[0] + B / A * (m[1] - m[0]);
}

VP crosspointCL(const C &c, const L &l) {
  VP ret;
  P mid = projection(l, c.p);
  double d = distanceLP(l, c.p);
  if (EQ(d, c.r)) {
    ret.push_back(mid);
  } else if (d < c.r) {
    double len = sqrt(c.r * c.r - d * d);
    ret.push_back(mid + len * unit(l[1] - l[0]));
    ret.push_back(mid - len * unit(l[1] - l[0]));
  }
  return ret;
}
VP crosspointCS(const C &c, const L &s) {
  VP ret;
  VP cp = crosspointCL(c, s);
  for (int i = 0; i < (int)cp.size(); i++) {
    if (intersectSP(s, cp[i])) {
      ret.push_back(cp[i]);
    }
  }
  return ret;
}

int main() {
  while (1) {
    int n;
    cin >> n;
    if (n == 0)
      break;

    double w, h, r, vx, vy;
    cin >> w >> h >> r >> vx >> vy;
    VP rec{P(r, r), P(w - r, r), P(w - r, h - r), P(r, h - r)};
    P dir = unit(P(vx, vy));

    VP p(n);
    for (int i = 0; i < n; i++) {
      double x, y;
      cin >> x >> y;
      p[i] = P(x, y);
    }

    P pos = p[0];
    double limit = 1e4;
    int ans = -1;
    while (limit > 0) {
      P ep = pos + dir * 1e4;
      L ray(pos, ep);
      bool touch = false;
      P cp(INF, INF);
      for (int i = 1; i < n; i++) {
        if (distanceSP(ray, p[i]) < 2 * r + EPS) {
          VP cpcs = crosspointCS(C(p[i], 2 * r), ray);
          for (P p : cpcs) {
            if (abs(pos - p) < abs(pos - cp)) {
              cp = p;
              ans = i + 1;
            }
          }
          touch = true;
        }
      }
      if (touch) {
        limit -= abs(pos - cp);
        break;
      }

      bool corner = false;
      for (int i = 0; i < 4; i++) {
        if (intersectSP(ray, rec[i])) {
          limit -= 2 * abs(pos - rec[i]);
          dir = -dir;
          corner = true;
          break;
        }
      }
      for (int i = 0; i < 4 && !corner; i++) {
        L edge(rec[i], rec[(i + 1) % 4]);
        if (!isParallel(ray, edge) && intersectSS(ray, edge)) {
          P cpll = crosspointLL(ray, edge);
          if (cpll == pos)
            continue;
          P to = reflection(edge, ep);
          limit -= abs(cpll - pos);
          pos = cpll;
          dir = unit(to - cpll);
          break;
        }
      }
    }

    if (limit < -EPS || ans == -1) {
      cout << -1 << endl;
    } else {
      cout << ans << endl;
    }
  }
  return 0;
}


Error: TLE

Fixed submission:

#include <algorithm>
#include <array>
#include <cmath>
#include <complex>
#include <iomanip>
#include <iostream>
#include <vector>
using namespace std;
const double EPS = 1e-8;
const double INF = 1e12;
#define EQ(n, m) (abs((n) - (m)) < EPS)
#define X real()
#define Y imag()

typedef complex<double> P;
typedef vector<P> VP;
struct L : array<P, 2> {
  L(const P &a, const P &b) {
    at(0) = a;
    at(1) = b;
  }
  L() {}
};
struct C {
  P p;
  double r;
  C(const P &p, const double &r) : p(p), r(r) {}
  C() {}
};

double dot(P a, P b) { return (conj(a) * b).X; }
double cross(P a, P b) { return (conj(a) * b).Y; }
int ccw(P a, P b, P c) {
  b -= a;
  c -= a;
  if (cross(b, c) > EPS)
    return +1; // ccw
  if (cross(b, c) < -EPS)
    return -1; // cw
  if (dot(b, c) < -EPS)
    return +2; // c-a-b
  if (abs(c) - abs(b) > EPS)
    return -2; // a-b-c
  return 0;    // a-c-b
}
P unit(const P &p) { return p / abs(p); }

double distanceLP(const L &l, const P &p) {
  return abs(cross(l[1] - l[0], p - l[0])) / abs(l[1] - l[0]);
}
double distanceSP(const L &s, const P &p) {
  if (dot(s[1] - s[0], p - s[0]) < EPS)
    return abs(p - s[0]);
  if (dot(s[0] - s[1], p - s[1]) < EPS)
    return abs(p - s[1]);
  return distanceLP(s, p);
}
bool intersectSP(const L &s, const P &p) {
  return abs(cross(s[0] - p, s[1] - p)) < EPS && dot(s[0] - p, s[1] - p) < EPS;
}
bool intersectSS(const L &a, const L &b) {
  return (ccw(a[0], a[1], b[0]) * ccw(a[0], a[1], b[1]) <= 0) &&
         (ccw(b[0], b[1], a[0]) * ccw(b[0], b[1], a[1]) <= 0);
}

P projection(const L &l, const P &p) {
  double t = dot(p - l[0], l[0] - l[1]) / norm(l[0] - l[1]);
  return l[0] + t * (l[0] - l[1]);
}
P reflection(const L &l, const P &p) {
  return p + 2.0 * (projection(l, p) - p);
}
bool isParallel(const P &a, const P &b) { return abs(cross(a, b)) < EPS; }
bool isParallel(const L &a, const L &b) {
  return isParallel(a[1] - a[0], b[1] - b[0]);
}

P crosspointLL(const L &l, const L &m) {
  double A = cross(l[1] - l[0], m[1] - m[0]);
  double B = cross(l[1] - l[0], l[1] - m[0]);
  return m[0] + B / A * (m[1] - m[0]);
}

VP crosspointCL(const C &c, const L &l) {
  VP ret;
  P mid = projection(l, c.p);
  double d = distanceLP(l, c.p);
  if (EQ(d, c.r)) {
    ret.push_back(mid);
  } else if (d < c.r) {
    double len = sqrt(c.r * c.r - d * d);
    ret.push_back(mid + len * unit(l[1] - l[0]));
    ret.push_back(mid - len * unit(l[1] - l[0]));
  }
  return ret;
}
VP crosspointCS(const C &c, const L &s) {
  VP ret;
  VP cp = crosspointCL(c, s);
  for (int i = 0; i < (int)cp.size(); i++) {
    if (intersectSP(s, cp[i])) {
      ret.push_back(cp[i]);
    }
  }
  return ret;
}

int main() {
  while (1) {
    int n;
    cin >> n;
    if (n == 0)
      break;

    double w, h, r, vx, vy;
    cin >> w >> h >> r >> vx >> vy;
    VP rec{P(r, r), P(w - r, r), P(w - r, h - r), P(r, h - r)};
    P dir = unit(P(vx, vy));

    VP p(n);
    for (int i = 0; i < n; i++) {
      double x, y;
      cin >> x >> y;
      p[i] = P(x, y);
    }

    P pos = p[0];
    double limit = 1e4;
    int ans = -1;
    while (limit > 0) {
      P ep = pos + dir * 1e4;
      L ray(pos, ep);
      bool touch = false;
      P cp(INF, INF);
      for (int i = 1; i < n; i++) {
        if (distanceSP(ray, p[i]) < 2 * r + EPS) {
          VP cpcs = crosspointCS(C(p[i], 2 * r), ray);
          for (P p : cpcs) {
            if (abs(pos - p) < abs(pos - cp)) {
              cp = p;
              ans = i + 1;
            }
          }
          touch = true;
        }
      }
      if (touch) {
        limit -= abs(pos - cp);
        break;
      }

      bool corner = false;
      for (int i = 0; i < 4; i++) {
        if (intersectSP(ray, rec[i])) {
          limit -= 2 * abs(pos - rec[i]);
          dir = -dir;
          corner = true;
          break;
        }
      }
      for (int i = 0; i < 4 && !corner; i++) {
        L edge(rec[i], rec[(i + 1) % 4]);
        if (!isParallel(ray, edge) && intersectSS(ray, edge)) {
          P cpll = crosspointLL(ray, edge);
          if (cpll == pos)
            continue;
          P to = reflection(edge, ep);
          limit -= abs(cpll - pos);
          pos = cpll;
          dir = unit(to - cpll);
          break;
        }
      }
    }

    if (limit < -EPS || ans == -1) {
      cout << -1 << endl;
    } else {
      cout << ans << endl;
    }
  }
  return 0;
}