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

#include <cassert>
#include <cmath>
#include <complex>
#include <cstdio>
#include <utility>
#include <vector>

using namespace std;

double eps = 1e-9;

typedef complex<double> Point;
typedef complex<double> Vector;

template <class T> bool eq(T a, T b) { return abs(a - b) < eps; }

template <class T> int sgn(T r) { return eq(r, 0.0) ? 0 : (r > 0 ? 1 : -1); }

struct Circle {
  Point center;
  double r;
  Circle(Point c, double r) : center(c), r(r) {}
  Circle() {}
};

struct Line {
  double a, b, c; // ax+by=c
  Line() {}
  Line(double a, double b, double c) : a(a), b(b), c(c) {}
  Line(Point p1, Point p2) { // not verified
    if (eq(abs(p1 - p2), 0.0)) {
      fprintf(stderr, "called Line for same points\\n");
      assert(0);
    }
    double x1 = p1.real(), y1 = p1.imag();
    double x2 = p2.real(), y2 = p2.imag();
    a = y2 - y1;
    b = -(x2 - x1);
    c = x1 * y2 - x2 * y1;
  }
};

void print(Point p) {
  if (isnan(p.real()) || isnan(p.imag())) {
    printf("NaN Point\\n");
    return;
  }
  printf("(%f,%f)\\n", p.real(), p.imag());
}

double pointsDistance(Point p1, Point p2) { /*abs(p1-p2)と書いてよい*/
  double dx = p1.real() - p2.real();
  double dy = p1.imag() - p2.imag();
  return sqrt(dx * dx + dy * dy);
}

double linePointDistance(Line l, Point p) {
  double a = l.a, b = l.b, c = l.c;
  double x = p.real(), y = p.imag();
  double num = abs(a * x + b * y - c);
  double den = sqrt(a * a + b * b);
  return num / den;
}

Vector basisVector(Vector v) {
  if (eq(v.real(), 0.0) && eq(v.imag(), 0.0))
    return v;
  return v / sqrt(norm(v));
}

Point linePointProjection(Line l, Point p) {
  double dx = l.a, dy = l.b;
  double a = l.a, b = l.b, c = l.c;
  double x = p.real(), y = p.imag();
  Vector ba = basisVector(Vector(dx, dy));
  double num = a * x + b * y - c;
  double den = sqrt(a * a + b * b);
  Vector v = ba * (-num / den);
  return p + v;
}

vector<Point> circleLineIntersection(Circle c, Line l) {
  vector<Point> res;
  Point p = linePointProjection(l, c.center);
  double d = linePointDistance(l, c.center);
  int s = sgn(d - c.r);
  if (s == 1) {
    return res; // empty
  } else if (s == 0) {
    res.push_back(p);
    return res;
  } else {
    double r = c.r;
    double t = sqrt(r * r - d * d);
    Vector e = basisVector(Vector(l.b, -l.a));
    res.push_back(p + t * e);
    res.push_back(p - t * e);
    return res;
  }
}

vector<Point> circlesIntersection(Circle c1,
                                  Circle c2) { /*一致するとき処理できない*/
  if (eq(c1.center.real(), c2.center.real()) &&
      eq(c1.center.imag(), c2.center.imag()) && eq(c1.r, c2.r)) {
    Point p = Point(NAN, NAN);
    vector<Point> v;
    v.push_back(p);
    return v;
  }
  double d = pointsDistance(c1.center, c2.center);
  double r1 = c1.r, r2 = c2.r;
  double dif = max(r1, r2) - min(r1, r2);
  double sum = r1 + r2;
  if (sgn(d - sum) == 1 || sgn(dif - d) == 1) { // d>sum||dif>d
    vector<Point> v;
    return v;
  }
  double x1 = c1.center.real(), y1 = c1.center.imag();
  double x2 = c2.center.real(), y2 = c2.center.imag();
  Line l = Line(-x1 * 2 + x2 * 2, -y1 * 2 + y2 * 2,
                r1 * r1 - r2 * r2 - (x1 * x1 - x2 * x2) - (y1 * y1 - y2 * y2));
  return circleLineIntersection(c1, l);
}

double det(double a, double b, double c, double d) { return a * d - b * c; }

Point linesIntersection(Line l1, Line l2) { /*平行の時は常にNAN*/
  double a = l1.a, b = l1.b, c = l1.c;
  double d = l2.a, e = l2.b, f = l2.c;
  double den = det(a, b, d, e);
  double numx = det(c, b, f, e);
  double numy = det(a, c, d, f);
  if (eq(den, 0.0)) {
    return Point(NAN, NAN);
  }
  return Point(numx / den, numy / den);
}

// circlesIntersection verify AOJ1190 ICPC Domestic 2013 Balloon

double crossProduct(Vector a, Vector b) { return (conj(a) * b).imag(); }

double dotProduct(Vector a, Vector b) { return (conj(a) * b).real(); }

int ccw(Point p1, Point p2, Point p3) {
  /*p1,p2,p3はすべて異なると仮定
  そうでない場合の戻り値は不定
  ではなく
  p1!=p2と仮定*/
  Vector b = p2 - p1;
  // Vector c=p3-p2;
  Vector c = p3 - p1;
  int s = sgn(crossProduct(b, c));
  if (s == 1)
    return 1; // counterclockwise
  if (s == -1)
    return -1; // clockwise
  int t = sgn(dotProduct(b, c));
  if (t == -1)
    return 2; // 3--1--2
  int u = sgn(norm(b) - norm(c));
  if (eq(norm(c), 0.0))
    return 0; // 1==3
  if (u == -1)
    return -2; // 1--2--3
  return 0;    // 1--3--2 or 2==3
}

struct Segment {
  Point p1, p2;
  Line l;
  Segment() {}
  Segment(Point p1, Point p2) : p1(p1), p2(p2) { l = Line(p1, p2); }
};

int oneLineCCW(Point p1, Point p2, Point p3) {
  /*p1!=p2かつp1,p2,p3は一直線上と仮定*/
  /*それ以外の時の戻り値は不定*/
  Vector b = p2 - p1, c = p3 - p1;
  if (sgn(dotProduct(b, c)) == -1)
    return 2; // p3--p1--p2
  if (eq(abs(p1 - p3), 0.0))
    return 1; // p1==p3--p2
  int s = sgn(norm(b) - norm(c));
  if (s == 1)
    return 0; // p1--p3--p2
  if (s == 0)
    return -1; // p1--p3==p2
  else
    return -2; // p1--p2--p3
}

double pointSegmentDistance(Point p, Segment s) {
  Line l = s.l;
  double d = linePointDistance(l, p);
  Point pr = linePointProjection(l, p);
  int x = oneLineCCW(s.p1, s.p2, pr);
  if (x >= -1 && x <= 1)
    return d;
  double a = abs(s.p1 - p);
  double b = abs(s.p2 - p);
  return min(a, b);
}

bool segmentsIntersect(Segment s1, Segment s2) {
  Point p[2], q[2];
  p[0] = s1.p1, p[1] = s1.p2;
  q[0] = s2.p1, q[1] = s2.p2;
  return ccw(p[0], p[1], q[0]) * ccw(p[0], p[1], q[1]) <= 0 &&
         ccw(q[0], q[1], p[0]) * ccw(q[0], q[1], p[1]) <= 0;
}

double segmentsDistance(Segment s1, Segment s2) {
  bool flg = segmentsIntersect(s1, s2);
  if (flg)
    return 0;
  Point p[2], q[2];
  p[0] = s1.p1, p[1] = s1.p2;
  q[0] = s2.p1, q[1] = s2.p2;
  double res = -1;
  for (int k = 0; k < 2; k++) {
    Point r = linePointProjection(s2.l, p[k]);
    if (abs(oneLineCCW(q[0], q[1], r)) <= 1) {
      double tmp = abs(r - p[k]);
      if (res < 0 || tmp < res)
        res = tmp;
    }
    r = linePointProjection(s1.l, q[k]);
    if (abs(oneLineCCW(p[0], p[1], r)) <= 1) {
      double tmp = abs(r - q[k]);
      if (res < 0 || tmp < res)
        res = tmp;
    }
  }
  for (int i = 0; i < 2; i++)
    for (int j = 0; j < 2; j++) {
      double tmp = abs(p[i] - q[j]);
      if (res < 0 || tmp < res)
        res = tmp;
    }
  return res;
}

// segmentsDistance verified aoj cgl_2 d Distance

Point inputPoint() {
  double x, y;
  scanf("%lf%lf", &x, &y);
  return Point(x, y);
}

int main() {
  int Q;
  scanf("%d", &Q);
  for (int datano = 0; datano < Q; datano++) {
    Point p1, p2;
    Point q1, q2;
    p1 = inputPoint();
    p2 = inputPoint();
    q1 = inputPoint();
    q2 = inputPoint();
    if (abs(p1 - p2) < eps)
      break;
    Segment s1 = Segment(p1, p2);
    Segment s2 = Segment(q1, q2);
    double ans = segmentsDistance(s1, s2);
    printf("%.9f\\n", ans);
  }
  return 0;
}

Error: TLE

Fixed submission:

#include <cassert>
#include <cmath>
#include <complex>
#include <cstdio>
#include <utility>
#include <vector>

using namespace std;

double eps = 1e-9;

typedef complex<double> Point;
typedef complex<double> Vector;

template <class T> bool eq(T a, T b) { return abs(a - b) < eps; }

template <class T> int sgn(T r) { return eq(r, 0.0) ? 0 : (r > 0 ? 1 : -1); }

struct Circle {
  Point center;
  double r;
  Circle(Point c, double r) : center(c), r(r) {}
  Circle() {}
};

struct Line {
  double a, b, c; // ax+by=c
  Line() {}
  Line(double a, double b, double c) : a(a), b(b), c(c) {}
  Line(Point p1, Point p2) { // not verified
    if (eq(abs(p1 - p2), 0.0)) {
      fprintf(stderr, "called Line for same points\\n");
      assert(0);
    }
    double x1 = p1.real(), y1 = p1.imag();
    double x2 = p2.real(), y2 = p2.imag();
    a = y2 - y1;
    b = -(x2 - x1);
    c = x1 * y2 - x2 * y1;
  }
};

void print(Point p) {
  if (isnan(p.real()) || isnan(p.imag())) {
    printf("NaN Point\\n");
    return;
  }
  printf("(%f,%f)\\n", p.real(), p.imag());
}

double pointsDistance(Point p1, Point p2) { /*abs(p1-p2)と書いてよい*/
  double dx = p1.real() - p2.real();
  double dy = p1.imag() - p2.imag();
  return sqrt(dx * dx + dy * dy);
}

double linePointDistance(Line l, Point p) {
  double a = l.a, b = l.b, c = l.c;
  double x = p.real(), y = p.imag();
  double num = abs(a * x + b * y - c);
  double den = sqrt(a * a + b * b);
  return num / den;
}

Vector basisVector(Vector v) {
  if (eq(v.real(), 0.0) && eq(v.imag(), 0.0))
    return v;
  return v / sqrt(norm(v));
}

Point linePointProjection(Line l, Point p) {
  double dx = l.a, dy = l.b;
  double a = l.a, b = l.b, c = l.c;
  double x = p.real(), y = p.imag();
  Vector ba = basisVector(Vector(dx, dy));
  double num = a * x + b * y - c;
  double den = sqrt(a * a + b * b);
  Vector v = ba * (-num / den);
  return p + v;
}

vector<Point> circleLineIntersection(Circle c, Line l) {
  vector<Point> res;
  Point p = linePointProjection(l, c.center);
  double d = linePointDistance(l, c.center);
  int s = sgn(d - c.r);
  if (s == 1) {
    return res; // empty
  } else if (s == 0) {
    res.push_back(p);
    return res;
  } else {
    double r = c.r;
    double t = sqrt(r * r - d * d);
    Vector e = basisVector(Vector(l.b, -l.a));
    res.push_back(p + t * e);
    res.push_back(p - t * e);
    return res;
  }
}

vector<Point> circlesIntersection(Circle c1,
                                  Circle c2) { /*一致するとき処理できない*/
  if (eq(c1.center.real(), c2.center.real()) &&
      eq(c1.center.imag(), c2.center.imag()) && eq(c1.r, c2.r)) {
    Point p = Point(NAN, NAN);
    vector<Point> v;
    v.push_back(p);
    return v;
  }
  double d = pointsDistance(c1.center, c2.center);
  double r1 = c1.r, r2 = c2.r;
  double dif = max(r1, r2) - min(r1, r2);
  double sum = r1 + r2;
  if (sgn(d - sum) == 1 || sgn(dif - d) == 1) { // d>sum||dif>d
    vector<Point> v;
    return v;
  }
  double x1 = c1.center.real(), y1 = c1.center.imag();
  double x2 = c2.center.real(), y2 = c2.center.imag();
  Line l = Line(-x1 * 2 + x2 * 2, -y1 * 2 + y2 * 2,
                r1 * r1 - r2 * r2 - (x1 * x1 - x2 * x2) - (y1 * y1 - y2 * y2));
  return circleLineIntersection(c1, l);
}

double det(double a, double b, double c, double d) { return a * d - b * c; }

Point linesIntersection(Line l1, Line l2) { /*平行の時は常にNAN*/
  double a = l1.a, b = l1.b, c = l1.c;
  double d = l2.a, e = l2.b, f = l2.c;
  double den = det(a, b, d, e);
  double numx = det(c, b, f, e);
  double numy = det(a, c, d, f);
  if (eq(den, 0.0)) {
    return Point(NAN, NAN);
  }
  return Point(numx / den, numy / den);
}

// circlesIntersection verify AOJ1190 ICPC Domestic 2013 Balloon

double crossProduct(Vector a, Vector b) { return (conj(a) * b).imag(); }

double dotProduct(Vector a, Vector b) { return (conj(a) * b).real(); }

int ccw(Point p1, Point p2, Point p3) {
  /*p1,p2,p3はすべて異なると仮定
  そうでない場合の戻り値は不定
  ではなく
  p1!=p2と仮定*/
  Vector b = p2 - p1;
  Vector c = p3 - p1;
  int s = sgn(crossProduct(b, c));
  if (s == 1)
    return 1; // counterclockwise
  if (s == -1)
    return -1; // clockwise
  int t = sgn(dotProduct(b, c));
  if (t == -1)
    return 2; // 3--1--2
  int u = sgn(norm(b) - norm(c));
  if (eq(norm(c), 0.0))
    return 0; // 1==3
  if (u == -1)
    return -2; // 1--2--3
  return 0;    // 1--3--2 or 2==3
}

struct Segment {
  Point p1, p2;
  Line l;
  Segment() {}
  Segment(Point p1, Point p2) : p1(p1), p2(p2) { l = Line(p1, p2); }
};

int oneLineCCW(Point p1, Point p2, Point p3) {
  /*p1!=p2かつp1,p2,p3は一直線上と仮定*/
  /*それ以外の時の戻り値は不定*/
  Vector b = p2 - p1, c = p3 - p1;
  if (!eq(crossProduct(b, c), 0.0))
    for (;;)
      ;
  if (sgn(dotProduct(b, c)) == -1)
    return 2; // p3--p1--p2
  if (eq(abs(p1 - p3), 0.0))
    return 1; // p1==p3--p2
  int s = sgn(norm(b) - norm(c));
  if (s == 1)
    return 0; // p1--p3--p2
  if (s == 0)
    return -1; // p1--p3==p2
  else
    return -2; // p1--p2--p3
}

double pointSegmentDistance(Point p, Segment s) {
  Line l = s.l;
  double d = linePointDistance(l, p);
  Point pr = linePointProjection(l, p);
  //  int x=oneLineCCW(s.p1,s.p2,pr);
  int x = ccw(s.p1, s.p2, pr);
  //  if(x>=-1&&x<=1) return d;
  if (x == 0)
    return d;
  double a = abs(s.p1 - p);
  double b = abs(s.p2 - p);
  return min(a, b);
}

bool segmentsIntersect(Segment s1, Segment s2) {
  Point p[2], q[2];
  p[0] = s1.p1, p[1] = s1.p2;
  q[0] = s2.p1, q[1] = s2.p2;
  return ccw(p[0], p[1], q[0]) * ccw(p[0], p[1], q[1]) <= 0 &&
         ccw(q[0], q[1], p[0]) * ccw(q[0], q[1], p[1]) <= 0;
}

double segmentsDistance(Segment s1, Segment s2) {
  bool flg = segmentsIntersect(s1, s2);
  if (flg)
    return 0;
  Point p[2], q[2];
  p[0] = s1.p1, p[1] = s1.p2;
  q[0] = s2.p1, q[1] = s2.p2;
  double res = -1;
  for (int k = 0; k < 2; k++) {
    Point r = linePointProjection(s2.l, p[k]);
    bool flg1 = (abs(oneLineCCW(q[0], q[1], r)) <= 1);
    bool flg2 = ccw(q[0], q[1], r) == 0;
    if (flg1 != flg2) {
      print(q[0]);
      print(q[1]);
      print(r);
      printf("%d %d\\n", oneLineCCW(q[0], q[1], r), ccw(q[0], q[1], r));
      assert(0);
    }
    //  if(abs(oneLineCCW(q[0],q[1],r))<=1){
    if (ccw(q[0], q[1], r) == 0) {
      double tmp = abs(r - p[k]);
      if (res < 0 || tmp < res)
        res = tmp;
    }
    r = linePointProjection(s1.l, q[k]);
    flg1 = abs(oneLineCCW(p[0], p[1], r)) <= 1;
    flg2 = ccw(p[0], p[1], r) == 0;
    if (flg1 != flg2) {
      print(p[0]);
      print(p[1]);
      print(r);
      printf("%d %d\\n", oneLineCCW(p[0], p[1], r), ccw(p[0], p[1], r));
      assert(0);
    }
    //  if(abs(oneLineCCW(p[0],p[1],r))<=1){
    if (ccw(p[0], p[1], r) == 0) {
      double tmp = abs(r - q[k]);
      if (res < 0 || tmp < res)
        res = tmp;
    }
  }
  for (int i = 0; i < 2; i++)
    for (int j = 0; j < 2; j++) {
      double tmp = abs(p[i] - q[j]);
      if (res < 0 || tmp < res)
        res = tmp;
    }
  return res;
}

// segmentsDistance verified aoj cgl_2 d Distance
Point inputPoint() {
  double x, y;
  scanf("%lf%lf", &x, &y);
  return Point(x, y);
}

int main() {
  int Q;
  scanf("%d", &Q);
  for (int datano = 0; datano < Q; datano++) {
    Point p1, p2;
    Point q1, q2;
    p1 = inputPoint();
    p2 = inputPoint();
    q1 = inputPoint();
    q2 = inputPoint();
    if (abs(p1 - p2) < eps)
      break;
    Segment s1 = Segment(p1, p2);
    Segment s2 = Segment(q1, q2);
    double ans = segmentsDistance(s1, s2);
    printf("%.9f\\n", ans);
  }
  return 0;
}