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

#include <algorithm>
#include <assert.h>
#include <iostream>
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <vector>

using namespace std;
typedef long long ll;
typedef unsigned int uint;
typedef unsigned long long ull;
static const double EPS = 1e-9;
static const double PI = acos(-1.0);

#define REP(i, n) for (int i = 0; i < (int)(n); i++)
#define FOR(i, s, n) for (int i = (s); i < (int)(n); i++)
#define FOREQ(i, s, n) for (int i = (s); i <= (int)(n); i++)
#define FORIT(it, c)                                                           \\
  for (__typeof((c).begin()) it = (c).begin(); it != (c).end(); it++)
#define MEMSET(v, h) memset((v), h, sizeof(v))

#include <complex>

typedef complex<double> Point;
typedef vector<Point> Polygon;

// static const double EPS = 1e-8;
static const double INF = 1e+10;

#define CURR(P, i) (P[i])
#define NEXT(P, i) (P[(i + 1) % P.size()])

struct Line : public vector<Point> {
  Line() { ; }
  Line(Point a, Point b) {
    push_back(a);
    push_back(b);
  }
};

inline double cross(const Point &a, const Point &b) {
  return imag(conj(a) * b);
}

inline double dot(const Point &a, const Point &b) { return real(conj(a) * b); }

inline int ccw(Point a, Point b, Point c) {
  b -= a;
  c -= a;
  if (cross(b, c) > 0) {
    return 1;
  }
  if (cross(b, c) < 0) {
    return -1;
  }
  if (dot(b, c) < 0) {
    return 2;
  }
  if (norm(b) < norm(c)) {
    return -2;
  }
  return 0;
}

bool intersectLL(const Line &l, const Line &m) {
  return abs(cross(l[1] - l[0], m[1] - m[0])) > EPS ||
         abs(cross(l[1] - l[0], m[0] - l[0])) < EPS;
}

bool intersectLS(const Line &l, const Line &s) {
  return cross(l[1] - l[0], s[0] - l[0]) * cross(l[1] - l[0], s[1] - l[0]) <
         EPS;
}

bool intersectLP(const Line &l, const Point &p) {
  return abs(cross(l[1] - p, l[0] - p)) < EPS;
}

bool intersectSS(const Line &s, const Line &t) {
  return ccw(s[0], s[1], t[0]) * ccw(s[0], s[1], t[1]) <= 0 &&
         ccw(t[0], t[1], s[0]) * ccw(t[0], t[1], s[1]) <= 0;
}

bool intersectSP(const Line &s, const Point &p) {
  return abs(s[0] - p) + abs(s[1] - p) - abs(s[1] - s[0]) < EPS;
}

Point projection(const Line &l, const Point &p) {
  double t = dot(p - l[0], l[0] - l[1]) / norm(l[0] - l[1]);
  return l[0] + t * (l[0] - l[1]);
}

Point reflection(const Line &l, const Point &p) {
  return p + 2.0 * (projection(l, p) - p);
}

double distanceLP(const Line &l, const Point &p) {
  return abs(p - projection(l, p));
}

double distanceLL(const Line &l, const Line &m) {
  return intersectLL(l, m) ? 0 : distanceLP(l, m[0]);
}

double distanceLS(const Line &l, const Line &s) {
  if (intersectLS(l, s)) {
    return 0;
  }
  return min(distanceLP(l, s[0]), distanceLP(l, s[1]));
}

double distanceSP(const Line &s, const Point &p) {
  const Point r = projection(s, p);
  if (intersectSP(s, r)) {
    return abs(r - p);
  }
  return min(abs(s[0] - p), abs(s[1] - p));
}

double distanceSS(const Line &s, const Line &t) {
  if (intersectSS(s, t)) {
    return 0;
  }
  return min(min(distanceSP(s, t[0]), distanceSP(s, t[1])),
             min(distanceSP(t, s[0]), distanceSP(t, s[1])));
}

Point crosspointSS(const Line &l, const Line &m) {
  double A = cross(l[1] - l[0], m[1] - m[0]);
  double B = cross(l[1] - l[0], l[1] - m[0]);
  if (abs(A) < EPS && abs(B) < EPS) {
    assert(false);
    if (intersectSP(l, m[0])) {
      return m[0];
    }
    if (intersectSP(l, m[1])) {
      return m[1];
    }
    if (intersectSP(m, l[0])) {
      return l[0];
    }
    if (intersectSP(m, l[1])) {
      return l[1];
    }
    return m[0];
  }
  if (abs(A) < EPS) {
    assert(false);
  }
  return m[0] + B / A * (m[1] - m[0]);
}

int n;
Point p[100];
pair<int, double> memo[1 << 10][10][10];

int OnLine(int used, const Line &l) {
  REP(i, n) {
    if ((used >> i) & 1) {
      continue;
    }
    if (intersectSP(l, p[i])) {
      used |= 1 << i;
    }
  }
  return used;
}

pair<int, double> calc(int used, int from, int to, int depth) {
  if (memo[used][from][to].first != -1) {
    return memo[used][from][to];
  }
  if ((used | (1 << to)) == (1 << n) - 1) {
    return make_pair(0, 0);
  }
  pair<int, double> ret(1000, 1e+10);
  // if (depth == 0) { return ret; }
  REP(nto, n) {
    if (nto == from) {
      continue;
    }
    if ((used >> nto) & 1) {
      continue;
    }
    REP(nfrom, n) {
      if (nfrom == nto) {
        continue;
      }
      if (((used >> nfrom) & 1) && nfrom != to) {
        continue;
      }
      Line pl = Line(p[to], p[to] + (p[to] - p[from]) * 1000.0);
      Line nl = Line(p[nfrom], p[nfrom] - (p[nto] - p[nfrom]) * 1000.0);
      if (!intersectSS(pl, nl)) {
        continue;
      }
      double A = cross(pl[1] - pl[0], nl[1] - nl[0]);
      if (abs(A) < EPS) {
        continue;
      }
      // cout << p[from] << " " << p[to] << " " << p[nfrom] << " " << p[nto] <<
      // endl; cout << pl[0] << " " << pl[1] << " " << nl[0] << " " << nl[1] <<
      // endl;
      Point cp = crosspointSS(pl, nl);
      pl = Line(p[to], cp);
      nl = Line(cp, p[nto]);
      int nused = used | (1 << nfrom) | (1 << nto);
      double ndist = abs(p[to] - cp) + abs(cp - p[nto]);
      nused = OnLine(nused, pl);
      nused = OnLine(nused, nl);

      pair<int, double> nret = calc(nused, nfrom, nto, depth - 1);
      nret.first++;
      nret.second += ndist;
      ret = min(ret, nret);
    }
  }
  return memo[used][from][to] = ret;
  // return ret;
}

int main() {
  while (scanf("%d", &n), n) {
    REP(i, n) {
      double x, y;
      scanf("%lf %lf", &x, &y);
      p[i] = Point(x, y);
    }
    pair<int, double> ans(1000, 1e+10);
    REP(iter, 100) {
      MEMSET(memo, -1);
      REP(i, n) {
        REP(j, n) {
          if (i == j) {
            continue;
          }
          int used = (1 << i) | (1 << j);
          used = OnLine(used, Line(p[i], p[j]));
          pair<int, double> nans = calc(used, i, j, iter);
          nans.second += abs(p[i] - p[j]);
          ans = min(ans, nans);
        }
      }
      if (ans.first <= 100) {
        break;
      }
    }
    printf("%d %.8f\\n", ans.first, ans.second);
  }
}

Error: TLE

Fixed submission:

#include <algorithm>
#include <assert.h>
#include <iostream>
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <vector>

using namespace std;
typedef long long ll;
typedef unsigned int uint;
typedef unsigned long long ull;
static const double EPS = 1e-9;
static const double PI = acos(-1.0);

#define REP(i, n) for (int i = 0; i < (int)(n); i++)
#define FOR(i, s, n) for (int i = (s); i < (int)(n); i++)
#define FOREQ(i, s, n) for (int i = (s); i <= (int)(n); i++)
#define FORIT(it, c)                                                           \\
  for (__typeof((c).begin()) it = (c).begin(); it != (c).end(); it++)
#define MEMSET(v, h) memset((v), h, sizeof(v))

#include <complex>

typedef complex<double> Point;
typedef vector<Point> Polygon;

// static const double EPS = 1e-8;
static const double INF = 1e+10;

#define CURR(P, i) (P[i])
#define NEXT(P, i) (P[(i + 1) % P.size()])

struct Line : public vector<Point> {
  Line() { ; }
  Line(Point a, Point b) {
    push_back(a);
    push_back(b);
  }
};

inline double cross(const Point &a, const Point &b) {
  return imag(conj(a) * b);
}

inline double dot(const Point &a, const Point &b) { return real(conj(a) * b); }

inline int ccw(Point a, Point b, Point c) {
  b -= a;
  c -= a;
  if (cross(b, c) > 0) {
    return 1;
  }
  if (cross(b, c) < 0) {
    return -1;
  }
  if (dot(b, c) < 0) {
    return 2;
  }
  if (norm(b) < norm(c)) {
    return -2;
  }
  return 0;
}

bool intersectLL(const Line &l, const Line &m) {
  return abs(cross(l[1] - l[0], m[1] - m[0])) > EPS ||
         abs(cross(l[1] - l[0], m[0] - l[0])) < EPS;
}

bool intersectLS(const Line &l, const Line &s) {
  return cross(l[1] - l[0], s[0] - l[0]) * cross(l[1] - l[0], s[1] - l[0]) <
         EPS;
}

bool intersectLP(const Line &l, const Point &p) {
  return abs(cross(l[1] - p, l[0] - p)) < EPS;
}

bool intersectSS(const Line &s, const Line &t) {
  return ccw(s[0], s[1], t[0]) * ccw(s[0], s[1], t[1]) <= 0 &&
         ccw(t[0], t[1], s[0]) * ccw(t[0], t[1], s[1]) <= 0;
}

bool intersectSP(const Line &s, const Point &p) {
  return abs(s[0] - p) + abs(s[1] - p) - abs(s[1] - s[0]) < EPS;
}

Point projection(const Line &l, const Point &p) {
  double t = dot(p - l[0], l[0] - l[1]) / norm(l[0] - l[1]);
  return l[0] + t * (l[0] - l[1]);
}

Point reflection(const Line &l, const Point &p) {
  return p + 2.0 * (projection(l, p) - p);
}

double distanceLP(const Line &l, const Point &p) {
  return abs(p - projection(l, p));
}

double distanceLL(const Line &l, const Line &m) {
  return intersectLL(l, m) ? 0 : distanceLP(l, m[0]);
}

double distanceLS(const Line &l, const Line &s) {
  if (intersectLS(l, s)) {
    return 0;
  }
  return min(distanceLP(l, s[0]), distanceLP(l, s[1]));
}

double distanceSP(const Line &s, const Point &p) {
  const Point r = projection(s, p);
  if (intersectSP(s, r)) {
    return abs(r - p);
  }
  return min(abs(s[0] - p), abs(s[1] - p));
}

double distanceSS(const Line &s, const Line &t) {
  if (intersectSS(s, t)) {
    return 0;
  }
  return min(min(distanceSP(s, t[0]), distanceSP(s, t[1])),
             min(distanceSP(t, s[0]), distanceSP(t, s[1])));
}

Point crosspointSS(const Line &l, const Line &m) {
  double A = cross(l[1] - l[0], m[1] - m[0]);
  double B = cross(l[1] - l[0], l[1] - m[0]);
  if (abs(A) < EPS && abs(B) < EPS) {
    assert(false);
    if (intersectSP(l, m[0])) {
      return m[0];
    }
    if (intersectSP(l, m[1])) {
      return m[1];
    }
    if (intersectSP(m, l[0])) {
      return l[0];
    }
    if (intersectSP(m, l[1])) {
      return l[1];
    }
    return m[0];
  }
  if (abs(A) < EPS) {
    assert(false);
  }
  return m[0] + B / A * (m[1] - m[0]);
}

int n;
Point p[100];
pair<int, double> memo[1 << 10][10][10];

pair<int, double> calc(int used, int from, int to) {
  if (memo[used][from][to].first != -1) {
    return memo[used][from][to];
  }
  if ((used | (1 << to)) == (1 << n) - 1) {
    return make_pair(0, 0);
  }
  pair<int, double> ret(1000, 1e+10);
  REP(nto, n) {
    if (nto == from) {
      continue;
    }
    if ((used >> nto) & 1) {
      continue;
    }
    REP(nfrom, n) {
      if (nfrom == nto) {
        continue;
      }
      Line pl = Line(p[to], p[to] + (p[to] - p[from]) * 1000.0);
      Line nl = Line(p[nfrom], p[nfrom] - (p[nto] - p[nfrom]) * 1000.0);
      if (!intersectSS(pl, nl)) {
        continue;
      }
      double A = cross(pl[1] - pl[0], nl[1] - nl[0]);
      if (abs(A) < EPS) {
        continue;
      }
      // cout << p[from] << " " << p[to] << " " << p[nfrom] << " " << p[nto] <<
      // endl; cout << pl[0] << " " << pl[1] << " " << nl[0] << " " << nl[1] <<
      // endl;
      Point cp = crosspointSS(pl, nl);
      pl = Line(p[to], cp);
      nl = Line(cp, p[nto]);

      int nused = used | (1 << nfrom) | (1 << nto);
      double ndist = abs(p[to] - cp) + abs(cp - p[nto]);
      REP(i, n) {
        if ((used >> i) & 1) {
          continue;
        }
        if (intersectSP(pl, p[i])) {
          nused |= 1 << i;
        }
        if (intersectSP(nl, p[i])) {
          nused |= 1 << i;
        }
      }
      pair<int, double> nret = calc(nused, nfrom, nto);
      nret.first++;
      nret.second += ndist;
      ret = min(ret, nret);
    }
  }
  return memo[used][from][to] = ret;
}

int main() {
  while (scanf("%d", &n), n) {
    MEMSET(memo, -1);
    REP(i, n) {
      double x, y;
      scanf("%lf %lf", &x, &y);
      p[i] = Point(x, y);
    }
    pair<int, double> ans(1000, 1e+10);
    REP(i, n) {
      REP(j, n) {
        if (i == j) {
          continue;
        }
        pair<int, double> nans = calc((1 << i) | (1 << j), i, j);
        nans.second += abs(p[i] - p[j]);
        ans = min(ans, nans);
      }
    }
    printf("%d %.8f\\n", ans.first, ans.second);
  }
}