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

#include <algorithm>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <string>
#include <vector>

using namespace std;

#define FOR(i, k, n) for (int i = (k); i < (int)(n); ++i)
#define REP(i, n) FOR(i, 0, n)
#define FORIT(i, c)                                                            \\
  for (__typeof((c).begin()) i = (c).begin(); i != (c).end(); ++i)

template <class T> void debug(T begin, T end) {
  for (T i = begin; i != end; ++i)
    cerr << *i << " ";
  cerr << endl;
}
inline bool valid(int x, int y, int W, int H) {
  return (x >= 0 && y >= 0 && x < W && y < H);
}

typedef long long ll;
const int INF = 100000000;
const double EPS = 1e-8;
const int MOD = 1000000007;
int dx[8] = {1, 0, -1, 0, 1, -1, -1, 1};
int dy[8] = {0, 1, 0, -1, 1, 1, -1, -1};
// 2次方程式 ax^2 + bx + c = 0の解 (重解を一つにまとめる)
vector<double> quadratic(double a, double b, double c) {
  // assert(a != 0);
  if (a < EPS) {
    if (b < EPS)
      return vector<double>();
    return vector<double>(1, -c / b);
  }
  double D = b * b - 4 * a * c;
  if (D < 0)
    return vector<double>();
  if (D == 0)
    return vector<double>(1, -b / (2.0 * a));

  // |b| >> |ac|の時の桁落ちを避けるために
  // x_1 = (-b-sign(b)*sqrt(D))/(2*a), x_2 = c / (a*x_1)を利用する
  vector<double> res;
  int sign = (b >= 0) ? 1 : -1;
  double x1 = (-b - sign * sqrt(D)) / (2.0 * a);
  double x2 = c / (a * x1);
  res.push_back(x1);
  res.push_back(x2);
  return res;
}
struct UnionFind {
  vector<int> data;
  UnionFind(int N) : data(N, -1) {}
  bool uni(int x, int y) {
    x = root(x);
    y = root(y);
    if (x != y) {
      if (data[x] > data[y])
        swap(x, y);
      data[x] += data[y];
      data[y] = x;
    }
    return x != y;
  }
  bool same(int x, int y) { return root(x) == root(y); }
  int root(int x) { return data[x] < 0 ? x : data[x] = root(data[x]); }
  int size(int x) { return -data[root(x)]; }
};
typedef double Weight;
struct Edge {
  int src, dst;
  Weight cost;
  Edge(int f, int t, Weight c) : src(f), dst(t), cost(c) {}
};
bool operator<(const Edge &a, const Edge &b) { return a.cost < b.cost; }
bool operator>(const Edge &a, const Edge &b) { return b < a; }
typedef vector<Edge> Node;
typedef vector<Node> Graph;
vector<Edge> kruskal(int N, const vector<Edge> &edges) {
  priority_queue<Edge, vector<Edge>, greater<Edge>> que;
  REP(i, edges.size()) que.push(edges[i]);
  UnionFind uf(N);
  vector<Edge> res;
  while (!que.empty()) {
    Edge e = que.top();
    que.pop();
    if (!uf.same(e.dst, e.src)) {
      uf.uni(e.dst, e.src);
      res.push_back(e);
    }
    if (res.size() == N - 1)
      break;
  }
  assert(res.size() == N - 1);
  return res;
}
// sqrt( at^2 + bt + c )
double f(double t, double a, double b, double c) {
  double res = a * t * t + b * t + c;
  return sqrt(res);
}
double MST(double t, const vector<Edge> &edges, double a[16][16],
           double b[16][16], double c[16][16]) {
  double res = 0;
  FORIT(e, edges) {
    res += f(t, a[e->src][e->dst], b[e->src][e->dst], c[e->src][e->dst]);
  }
  return res;
}
int main() {
  int N, T;
  while (cin >> N >> T && N) {
    double x[16], y[16];
    double vx[16], vy[16];
    REP(i, N) cin >> x[i] >> y[i] >> vx[i] >> vy[i];
    double a[16][16]; // (v[i] - v[j]) * (v[i] - v[j])
    double b[16][16]; // (p[i] - p[j]) * (v[i] - v[j])
    double c[16][16]; // (p[i] - p[j]) * (p[i] - p[j])
    vector<double> inter_point;
    inter_point.push_back(0);
    inter_point.push_back(T);
    REP(i, N) FOR(j, i + 1, N) {
      double dx = x[i] - x[j];
      double dy = y[i] - y[j];
      double vdx = vx[i] - vx[j];
      double vdy = vy[i] - vy[j];
      a[i][j] = vdx * vdx + vdy * vdy;
      b[i][j] = 2 * (dx * vdx + dy * vdy);
      c[i][j] = dx * dx + dy * dy;
      // printf("%d -> %d: a = %lf b = %lf c = %lf\\n", i, j, a[i][j], b[i][j],
      // c[i][j]);
    }
    REP(i, N) FOR(j, i + 1, N) REP(k, N) FOR(l, k + 1, N) {
      vector<double> v =
          quadratic(a[i][j] - a[k][l], b[i][j] - b[k][l], c[i][j] - c[k][l]);
      REP(i, v.size()) {
        double t = v[i];
        bool ok = (0 + EPS < t && t < T - EPS);
        REP(i, inter_point.size())
        if (abs(t - inter_point[i]) < EPS) ok = false;
        if (ok)
          inter_point.insert(
              lower_bound(inter_point.begin(), inter_point.end(), t), t);
      }
    }
    double ans = 1e40;
    REP(i, inter_point.size() - 1) {
      double lb = inter_point[i], ub = inter_point[i + 1];
      vector<Edge> edges;
      REP(i, N) FOR(j, i + 1, N) {
        edges.push_back(
            Edge(i, j, f((lb + ub) / 2, a[i][j], b[i][j], c[i][j])));
      }
      edges = kruskal(N, edges);
      REP(iter, 60) {
        if (MST((lb * 2 + ub) / 3, edges, a, b, c) <
            MST((lb + ub * 2) / 3, edges, a, b, c)) {
          ub = (lb + ub * 2) / 3;
        } else {
          lb = (lb * 2 + ub) / 3;
        }
      }
      ans = min(ans, MST((lb + ub) / 2, edges, a, b, c));
    }
    printf("%.10lf\\n", ans);
  }
  return 0;
}

Error: TLE

Fixed submission:

#include <algorithm>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <string>
#include <vector>

using namespace std;

#define FOR(i, k, n) for (int i = (k); i < (int)(n); ++i)
#define REP(i, n) FOR(i, 0, n)
#define FORIT(i, c)                                                            \\
  for (__typeof((c).begin()) i = (c).begin(); i != (c).end(); ++i)

template <class T> void debug(T begin, T end) {
  for (T i = begin; i != end; ++i)
    cerr << *i << " ";
  cerr << endl;
}
inline bool valid(int x, int y, int W, int H) {
  return (x >= 0 && y >= 0 && x < W && y < H);
}

typedef long long ll;
const int INF = 100000000;
const double EPS = 1e-8;
const int MOD = 1000000007;
int dx[8] = {1, 0, -1, 0, 1, -1, -1, 1};
int dy[8] = {0, 1, 0, -1, 1, 1, -1, -1};
// 2次方程式 ax^2 + bx + c = 0の解 (重解を一つにまとめる)
vector<double> quadratic(double a, double b, double c) {
  // assert(a != 0);
  if (a < EPS) {
    if (b < EPS)
      return vector<double>();
    return vector<double>(1, -c / b);
  }
  double D = b * b - 4 * a * c;
  if (D < 0)
    return vector<double>();
  if (D == 0)
    return vector<double>(1, -b / (2.0 * a));

  // |b| >> |ac|の時の桁落ちを避けるために
  // x_1 = (-b-sign(b)*sqrt(D))/(2*a), x_2 = c / (a*x_1)を利用する
  vector<double> res;
  int sign = (b >= 0) ? 1 : -1;
  double x1 = (-b - sign * sqrt(D)) / (2.0 * a);
  double x2 = c / (a * x1);
  res.push_back(x1);
  res.push_back(x2);
  return res;
}
struct UnionFind {
  vector<int> data;
  UnionFind(int N) : data(N, -1) {}
  bool uni(int x, int y) {
    x = root(x);
    y = root(y);
    if (x != y) {
      if (data[x] > data[y])
        swap(x, y);
      data[x] += data[y];
      data[y] = x;
    }
    return x != y;
  }
  bool same(int x, int y) { return root(x) == root(y); }
  int root(int x) { return data[x] < 0 ? x : data[x] = root(data[x]); }
  int size(int x) { return -data[root(x)]; }
};
typedef double Weight;
struct Edge {
  int src, dst;
  Weight cost;
  Edge(int f, int t, Weight c) : src(f), dst(t), cost(c) {}
};
bool operator<(const Edge &a, const Edge &b) { return a.cost < b.cost; }
bool operator>(const Edge &a, const Edge &b) { return b < a; }
typedef vector<Edge> Node;
typedef vector<Node> Graph;
double kruskal(int N, vector<Edge> &edges) {
  priority_queue<Edge, vector<Edge>, greater<Edge>> que;
  REP(i, edges.size()) que.push(edges[i]);
  UnionFind uf(N);
  int SIZE = 1;
  double res = 0;
  while (!que.empty()) {
    Edge e = que.top();
    que.pop();
    if (!uf.same(e.dst, e.src)) {
      uf.uni(e.dst, e.src);
      res += e.cost;
      SIZE++;
    }
    if (SIZE == N)
      break;
  }
  assert(SIZE == N);
  return res;
}
// sqrt( at^2 + bt + c )
double f(double t, double a, double b, double c) {
  double res = a * t * t + b * t + c;
  return sqrt(res);
}
double MST(double t, int N, double a[16][16], double b[16][16],
           double c[16][16]) {
  vector<Edge> edges;
  REP(i, N) FOR(j, i + 1, N) {
    edges.push_back(Edge(i, j, f(t, a[i][j], b[i][j], c[i][j])));
  }
  double res = kruskal(N, edges);
  // printf("%lf %lf\\n", t, res);
  return res;
}
int main() {
  int N, T;
  while (cin >> N >> T && N) {
    double x[16], y[16];
    double vx[16], vy[16];
    REP(i, N) cin >> x[i] >> y[i] >> vx[i] >> vy[i];
    double a[16][16]; // (v[i] - v[j]) * (v[i] - v[j])
    double b[16][16]; // (p[i] - p[j]) * (v[i] - v[j])
    double c[16][16]; // (p[i] - p[j]) * (p[i] - p[j])
    vector<double> inter_point;
    inter_point.push_back(0);
    inter_point.push_back(T);
    REP(i, N) FOR(j, i + 1, N) {
      double dx = x[i] - x[j];
      double dy = y[i] - y[j];
      double vdx = vx[i] - vx[j];
      double vdy = vy[i] - vy[j];
      a[i][j] = vdx * vdx + vdy * vdy;
      b[i][j] = 2 * (dx * vdx + dy * vdy);
      c[i][j] = dx * dx + dy * dy;
      // printf("%d -> %d: a = %lf b = %lf c = %lf\\n", i, j, a[i][j], b[i][j],
      // c[i][j]);
    }
    REP(i, N) FOR(j, i + 1, N) REP(k, N) FOR(l, k + 1, N) {
      vector<double> v =
          quadratic(a[i][j] - a[k][l], b[i][j] - b[k][l], c[i][j] - c[k][l]);
      REP(i, v.size()) {
        double t = v[i];
        bool ok = (0 + EPS < t && t < T - EPS);
        REP(i, inter_point.size())
        if (abs(t - inter_point[i]) < EPS) ok = false;
        if (ok)
          inter_point.insert(
              lower_bound(inter_point.begin(), inter_point.end(), t), t);
      }
    }
    double ans = 1e40;
    REP(i, inter_point.size() - 1) {
      double lb = inter_point[i], ub = inter_point[i + 1];
      REP(iter, 100) {
        if (MST((lb * 2 + ub) / 3, N, a, b, c) <
            MST((lb + ub * 2) / 3, N, a, b, c)) {
          ub = (lb + ub * 2) / 3;
        } else {
          lb = (lb * 2 + ub) / 3;
        }
      }
      ans = min(ans, MST((lb + ub) / 2, N, a, b, c));
    }
    printf("%.10lf\\n", ans);
  }
  return 0;
}