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

#include <algorithm>
#include <cmath>
#include <complex>
#include <iomanip>
#include <iostream>
#include <utility>
#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;
bool operator==(const P &a, const P &b) { return abs(a - b) < EPS; }

double dot(P a, P b) { return (conj(a) * b).X; }
double cross(P a, P b) { return (conj(a) * b).Y; }

double getarea(const VP &poly) {
  int n = poly.size();
  double ret = 0;
  for (int i = 0; i < n; i++) {
    ret += cross(poly[i], poly[(i + 1) % n]);
  }
  return ret * 0.5;
}

int dx[4] = {1, 1, -1, -1};
int dy[4] = {1, -1, 1, -1};
vector<vector<pair<int, int>>> xy;
VP p;

int dfs(int now, int end, const vector<int> &len) {
  if (now == end) {
    if (p[end] == P(0, 0)) {
      return getarea(p) + EPS;
    }
    return -1;
  }

  int remain = 0;
  for (int i = now + 1; i < end; i++) {
    remain += len[i];
  }
  int ret = -1;
  for (int i = 0; i < (int)xy[len[now]].size(); i++) {
    int x = xy[len[now]][i].first;
    int y = xy[len[now]][i].second;
    if (now == 0 && x > y)
      break; // 45度以下
    for (int d = 0; d < 4; d++) {
      p[now + 1] = p[now] + P(x * dx[d], y * dy[d]);
      if (now > 0) {
        P edge[4] = {p[now] - p[now - 1], p[now + 1] - p[now],
                     p[0] - p[now + 1], p[1] - p[0]};
        // 折れ曲がる方向
        if ((cross(edge[0], edge[1]) < -EPS ||
             (abs(cross(edge[0], edge[1])) < EPS &&
              dot(edge[0], edge[1]) < 0))) {
          continue;
        }
        // 閉じるために曲がる方向
        if ((cross(edge[1], edge[2]) < -EPS ||
             (abs(cross(edge[1], edge[2])) < EPS &&
              dot(edge[1], edge[2]) < 0))) {
          continue;
        }
        // 閉じたときの曲がる方向
        if ((cross(edge[2], edge[3]) < -EPS ||
             (abs(cross(edge[2], edge[3])) < EPS &&
              dot(edge[2], edge[3]) < 0))) {
          continue;
        }
      }
      // 囲めない
      if (abs(p[now + 1]) > remain + EPS) {
        continue;
      }
      ret = max(ret, dfs(now + 1, end, len));
      // 1本目は第一象限のみ
      if (now == 0)
        break;
    }
  }
  return ret;
}

int main() {
  xy.resize(301);
  for (int l = 0; l <= 300; l++) {
    for (int x = 0; x <= l; x++) {
      for (int y = 0; y <= l; y++) {
        if (x * x + y * y == l * l) {
          xy[l].emplace_back(x, y);
        }
      }
    }
  }
  while (1) {
    int n;
    cin >> n;
    if (n == 0)
      break;

    vector<int> l(n);
    for (int i = 0; i < n; i++) {
      cin >> l[i];
    }

    int ans = -1;
    sort(l.begin(), l.end());
    p.resize(n + 1);
    p[0] = P(0, 0);
    do {
      ans = max(ans, dfs(0, n, l));
    } while (next_permutation(l.begin() + 1, l.end())); // 1本目は固定でよい
    cout << fixed << setprecision(0);
    cout << ans << endl;
  }
}


Error: TLE

Fixed submission:

#include <algorithm>
#include <cmath>
#include <complex>
#include <iomanip>
#include <iostream>
#include <utility>
#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;
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; }

double dot(P a, P b) { return (conj(a) * b).X; }
double cross(P a, P b) { return (conj(a) * b).Y; }

double getarea(const VP &poly) {
  double ret = 0;
  for (int i = 0; i < (int)poly.size(); i++) {
    ret += cross(poly[i], poly[(i + 1) % poly.size()]);
  }
  return ret * 0.5;
}

int dx[4] = {1, 1, -1, -1};
int dy[4] = {1, -1, 1, -1};
vector<vector<pair<int, int>>> xy;

int dfs(int now, int end, const vector<int> &len, VP &p) {
  if (now == end) {
    if (p[end] == P(0, 0)) {
      return getarea(p) + EPS;
    }
    return -1;
  }

  int remain = 0;
  for (int i = now + 1; i < end; i++) {
    remain += len[i];
  }
  int ret = -1;
  for (int i = 0; i < (int)xy[len[now]].size(); i++) {
    int x = xy[len[now]][i].first;
    int y = xy[len[now]][i].second;
    for (int d = 0; d < 4; d++) {
      p[now + 1] = p[now] + P(x * dx[d], y * dy[d]);
      if (now > 0) {
        P edge[4] = {p[now] - p[now - 1], p[now + 1] - p[now],
                     p[0] - p[now + 1], p[1] - p[0]};
        // 折れ曲がる方向
        if ((cross(edge[0], edge[1]) < -EPS ||
             (abs(cross(edge[0], edge[1])) < EPS &&
              dot(edge[0], edge[1]) < 0))) {
          continue;
        }
        // 閉じるために曲がる方向
        if ((cross(edge[1], edge[2]) < -EPS ||
             (abs(cross(edge[1], edge[2])) < EPS &&
              dot(edge[1], edge[2]) < 0))) {
          continue;
        }
        // 閉じたときの曲がる方向
        if ((cross(edge[2], edge[3]) < -EPS ||
             (abs(cross(edge[2], edge[3])) < EPS &&
              dot(edge[2], edge[3]) < 0))) {
          continue;
        }
      }
      // 囲めない
      if (abs(p[now + 1]) > remain + EPS) {
        continue;
      }
      // 自己交差
      if (now + 1 != end && p[now + 1] == p[0]) {
        continue;
      }
      ret = max(ret, dfs(now + 1, end, len, p));
      // 1本目は第一象限のみ
      if (now == 0)
        break;
    }
  }
  return ret;
}

int main() {
  xy.resize(301);
  for (int l = 0; l <= 300; l++) {
    for (int x = 0; x <= l; x++) {
      for (int y = 0; y <= l; y++) {
        if (x * x + y * y == l * l) {
          xy[l].emplace_back(x, y);
        }
      }
    }
  }
  while (1) {
    int n;
    cin >> n;
    if (n == 0)
      break;

    vector<int> l(n);
    for (int i = 0; i < n; i++) {
      cin >> l[i];
    }

    int ans = -1;
    sort(l.begin(), l.end());
    VP p(n + 1, P(0, 0));
    do {
      ans = max(ans, dfs(0, n, l, p));
    } while (next_permutation(l.begin() + 1, l.end()));
    cout << fixed << setprecision(0);
    cout << ans << endl;
  }
}