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

#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (int)n; i++)
#define all(c) (c).begin(), (c).end()
#define pb push_back
#define dbg(...)                                                               \\
  do {                                                                         \\
    cerr << __LINE__ << ": ";                                                  \\
    dbgprint(#__VA_ARGS__, __VA_ARGS__);                                       \\
  } while (0);

using namespace std;

namespace std {
template <class S, class T> struct hash<pair<S, T>> {
  size_t operator()(const pair<S, T> &p) const {
    return ((size_t)1e9 + 7) * hash<S>()(p.first) + hash<T>()(p.second);
  }
};
template <class T> struct hash<vector<T>> {
  size_t operator()(const vector<T> &v) const {
    size_t h = 0;
    for (auto i : v)
      h = h * ((size_t)1e9 + 7) + hash<T>()(i) + 1;
    return h;
  }
};
} // namespace std
template <class T> ostream &operator<<(ostream &os, const vector<T> &v) {
  os << "[ ";
  rep(i, v.size()) os << v[i] << (i == v.size() - 1 ? " ]" : ", ");
  return os;
}
template <class T> ostream &operator<<(ostream &os, const set<T> &v) {
  os << "{ ";
  for (const auto &i : v)
    os << i << ", ";
  return os << "}";
}
template <class T, class U>
ostream &operator<<(ostream &os, const map<T, U> &v) {
  os << "{";
  for (const auto &i : v)
    os << " " << i.first << ": " << i.second << ",";
  return os << "}";
}
template <class T, class U>
ostream &operator<<(ostream &os, const pair<T, U> &p) {
  return os << "(" << p.first << ", " << p.second << ")";
}
void dbgprint(const string &fmt) { cerr << endl; }
template <class H, class... T>
void dbgprint(const string &fmt, const H &h, const T &...r) {
  cerr << fmt.substr(0, fmt.find(",")) << "= " << h << " ";
  dbgprint(fmt.substr(fmt.find(",") + 1), r...);
}
typedef long long ll;
typedef vector<int> vi;
typedef pair<int, int> pi;
const double EPS = 1e-8, INF = 1e12, PI = acos(-1.0);
typedef complex<double> P;
namespace std {
bool operator<(const P &a, const P &b) {
  return real(a) != real(b) ? real(a) < real(b) : imag(a) < imag(b);
}
} // namespace std
inline double cross(const P &a, const P &b) { return imag(conj(a) * b); }
inline double dot(const P &a, const P &b) { return real(conj(a) * b); }
struct L : public vector<P> {
  L(const P &a, const P &b) {
    push_back(a);
    push_back(b);
  }
};
typedef vector<P> G;
inline int ccw(P a, P b, P c) {
  b -= a;
  c -= a;
  if (cross(b, c) > EPS)
    return +1; // counter clockwise
  if (cross(b, c) < -EPS)
    return -1; // clockwise
  if (dot(b, c) < -EPS)
    return +2; // c--a--b on line
  if (norm(b) + EPS < norm(c))
    return -2; // a--b--c on line
  return 0;    // c is between a and b (inclusive)
}
bool intersectLS(const L &l, const L &s) {
  return cross(l[1] - l[0], s[0] - l[0]) * // s[0] is left of l
             cross(l[1] - l[0], s[1] - l[0]) <
         EPS; // s[1] is right of l
}
bool intersectSS(const L &s, const L &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;
}
P crosspoint(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]);
  if (abs(A) < EPS && abs(B) < EPS)
    return m[0]; // same line
  if (abs(A) < EPS)
    assert(false); // !!!PRECONDITION NOT SATISFIED!!!
  return m[0] + B / A * (m[1] - m[0]);
}
G convex_hull(G ps) {
  int n = ps.size(), k = 0;
  sort(ps.begin(), ps.end());
  G ch(2 * n);
  for (int i = 0; i < n; ch[k++] = ps[i++]) // lower-hull
    while (k >= 2 && ccw(ch[k - 2], ch[k - 1], ps[i]) <= 0)
      --k;
  for (int i = n - 2, t = k + 1; i >= 0; ch[k++] = ps[i--]) // upper-hull
    while (k >= t && ccw(ch[k - 2], ch[k - 1], ps[i]) <= 0)
      --k;
  ch.resize(k - 1);
  return ch;
}
#define curr(P, i) P[i]
#define next(P, i) P[(i + 1) % P.size()]
double area2(const G &g) {
  double A = 0;
  for (int i = 0; i < g.size(); ++i)
    A += cross(curr(g, i), next(g, i));
  return A;
}
enum { OUT, ON, IN };
int contains(const G &g, const P &p) {
  bool in = false;
  for (int i = 0; i < g.size(); ++i) {
    P a = curr(g, i) - p, b = next(g, i) - p;
    if (imag(a) > imag(b) + EPS)
      swap(a, b);
    if (imag(a) < EPS && EPS < imag(b))
      if (cross(a, b) < -EPS)
        in = !in;
    if (abs(cross(a, b)) < EPS && dot(a, b) < EPS)
      return ON;
  }
  return in ? IN : OUT;
}

int main() {
  cin.tie(0);
  cin.sync_with_stdio(0);
  int n;
  while (cin >> n, n) {
    G ps;
    rep(i, n) {
      int x, y;
      cin >> x >> y;
      ps.emplace_back(x, y);
    }
    // 各辺を任意の二頂点を結ぶ直線との交点で分割
    vector<G> points;
    rep(i, n) {
      G pts = {ps[i], ps[(i + 1) % n]};
      L e(ps[i], ps[(i + 1) % n]);
      rep(j, n) rep(k, j) {
        L l(ps[j], ps[k]);
        if (!intersectLS(l, e))
          continue;
        pts.pb(crosspoint(l, e));
      }
      sort(all(pts), [&](P a, P b) { return abs(ps[i] - a) < abs(ps[i] - b); });
      // 近い点は消す
      rep(j, (int)pts.size() - 1) if (abs(pts[j] - pts[j + 1]) < EPS) {
        pts.erase(pts.begin() + j);
        j--;
      }
      // 中点を足す
      int sz = (int)pts.size() - 1;
      rep(j, sz) pts.pb((pts[j] + pts[j + 1]) / 2.0);
      sort(all(pts), [&](P a, P b) { return abs(ps[i] - a) < abs(ps[i] - b); });
      swap(pts[1], pts.back());
      points.pb(pts);
    }
    // rep(i, n) dbg(i, points[i]);

    vector<vi> flags;
    for (const auto &pts : points) {
      vi fs;
      for (const P &p : pts) {
        int f = 0;
        rep(i, n) {
          L l(p, ps[i]);
          G crs = {l[0], l[1]};

          // 辺と交差してたらダメ
          rep(j, n) {
            L e(ps[j], ps[(j + 1) % n]);
            if (intersectSS(l, e))
              goto NG;
          }

          // 外に出てたらダメ
          rep(j, n) if (ccw(l[0], ps[j], l[1]) == -2) crs.pb(ps[j]);
          sort(all(crs),
               [&](P a, P b) { return abs(l[0] - a) < abs(l[0] - b); });
          rep(j, (int)crs.size() - 1) {
            if (contains(ps, (crs[j] + crs[j + 1]) / 2.0) == OUT) {
              /*
              dbg(crs[j], crs[j+1]);
              dbg((crs[j] + crs[j+1]) / 2.0);
              */
              goto NG;
            }
          }
          f |= 1 << i;
        NG:;
        }
        fs.pb(f);
      }
      flags.pb(fs);
    }

    int ans = (n + 1) / 2;
    rep(mask, 1 << n) {
      int sz = __builtin_popcount(mask);
      if (sz >= ans)
        continue;

      for (const vi fs : flags)
        for (int f : fs)
          if (!(f & mask))
            goto NEXT;

      ans = min(ans, sz);
    NEXT:;
    }
    cout << ans << endl;
  }
  return 0;
}


Error: TLE

Fixed submission:

#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (int)n; i++)
#define all(c) (c).begin(), (c).end()
#define pb push_back
#define dbg(...)                                                               \\
  do {                                                                         \\
    cerr << __LINE__ << ": ";                                                  \\
    dbgprint(#__VA_ARGS__, __VA_ARGS__);                                       \\
  } while (0);

using namespace std;

namespace std {
template <class S, class T> struct hash<pair<S, T>> {
  size_t operator()(const pair<S, T> &p) const {
    return ((size_t)1e9 + 7) * hash<S>()(p.first) + hash<T>()(p.second);
  }
};
template <class T> struct hash<vector<T>> {
  size_t operator()(const vector<T> &v) const {
    size_t h = 0;
    for (auto i : v)
      h = h * ((size_t)1e9 + 7) + hash<T>()(i) + 1;
    return h;
  }
};
} // namespace std
template <class T> ostream &operator<<(ostream &os, const vector<T> &v) {
  os << "[ ";
  rep(i, v.size()) os << v[i] << (i == v.size() - 1 ? " ]" : ", ");
  return os;
}
template <class T> ostream &operator<<(ostream &os, const set<T> &v) {
  os << "{ ";
  for (const auto &i : v)
    os << i << ", ";
  return os << "}";
}
template <class T, class U>
ostream &operator<<(ostream &os, const map<T, U> &v) {
  os << "{";
  for (const auto &i : v)
    os << " " << i.first << ": " << i.second << ",";
  return os << "}";
}
template <class T, class U>
ostream &operator<<(ostream &os, const pair<T, U> &p) {
  return os << "(" << p.first << ", " << p.second << ")";
}
void dbgprint(const string &fmt) { cerr << endl; }
template <class H, class... T>
void dbgprint(const string &fmt, const H &h, const T &...r) {
  cerr << fmt.substr(0, fmt.find(",")) << "= " << h << " ";
  dbgprint(fmt.substr(fmt.find(",") + 1), r...);
}
typedef long long ll;
typedef vector<int> vi;
typedef pair<int, int> pi;
const double EPS = 1e-8, INF = 1e12, PI = acos(-1.0);
typedef complex<double> P;
namespace std {
bool operator<(const P &a, const P &b) {
  return real(a) != real(b) ? real(a) < real(b) : imag(a) < imag(b);
}
} // namespace std
inline double cross(const P &a, const P &b) { return imag(conj(a) * b); }
inline double dot(const P &a, const P &b) { return real(conj(a) * b); }
struct L : public vector<P> {
  L(const P &a, const P &b) {
    push_back(a);
    push_back(b);
  }
};
typedef vector<P> G;
inline int ccw(P a, P b, P c) {
  b -= a;
  c -= a;
  if (cross(b, c) > EPS)
    return +1; // counter clockwise
  if (cross(b, c) < -EPS)
    return -1; // clockwise
  if (dot(b, c) < -EPS)
    return +2; // c--a--b on line
  if (norm(b) + EPS < norm(c))
    return -2; // a--b--c on line
  return 0;    // c is between a and b (inclusive)
}
bool intersectLS(const L &l, const L &s) {
  return cross(l[1] - l[0], s[0] - l[0]) * // s[0] is left of l
             cross(l[1] - l[0], s[1] - l[0]) <
         EPS; // s[1] is right of l
}
bool intersectSS(const L &s, const L &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;
}
P crosspoint(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]);
  if (abs(A) < EPS && abs(B) < EPS)
    return m[0]; // same line
  if (abs(A) < EPS)
    assert(false); // !!!PRECONDITION NOT SATISFIED!!!
  return m[0] + B / A * (m[1] - m[0]);
}
G convex_hull(G ps) {
  int n = ps.size(), k = 0;
  sort(ps.begin(), ps.end());
  G ch(2 * n);
  for (int i = 0; i < n; ch[k++] = ps[i++]) // lower-hull
    while (k >= 2 && ccw(ch[k - 2], ch[k - 1], ps[i]) <= 0)
      --k;
  for (int i = n - 2, t = k + 1; i >= 0; ch[k++] = ps[i--]) // upper-hull
    while (k >= t && ccw(ch[k - 2], ch[k - 1], ps[i]) <= 0)
      --k;
  ch.resize(k - 1);
  return ch;
}
#define curr(P, i) P[i]
#define next(P, i) P[(i + 1) % P.size()]
double area2(const G &g) {
  double A = 0;
  for (int i = 0; i < g.size(); ++i)
    A += cross(curr(g, i), next(g, i));
  return A;
}
enum { OUT, ON, IN };
int contains(const G &g, const P &p) {
  bool in = false;
  for (int i = 0; i < g.size(); ++i) {
    P a = curr(g, i) - p, b = next(g, i) - p;
    if (imag(a) > imag(b) + EPS)
      swap(a, b);
    if (imag(a) < EPS && EPS < imag(b))
      if (cross(a, b) < -EPS)
        in = !in;
    if (abs(cross(a, b)) < EPS && dot(a, b) < EPS)
      return ON;
  }
  return in ? IN : OUT;
}

int main() {
  cin.tie(0);
  cin.sync_with_stdio(0);
  int n;
  while (cin >> n, n) {
    G ps;
    rep(i, n) {
      int x, y;
      cin >> x >> y;
      ps.emplace_back(x, y);
    }
    // 各辺を任意の二頂点を結ぶ直線との交点で分割
    vector<G> points;
    rep(i, n) {
      G pts = {ps[i], ps[(i + 1) % n]};
      L e(ps[i], ps[(i + 1) % n]);
      rep(j, n) rep(k, j) {
        L l(ps[j], ps[k]);
        if (!intersectLS(l, e))
          continue;
        pts.pb(crosspoint(l, e));
      }
      sort(all(pts), [&](P a, P b) { return abs(ps[i] - a) < abs(ps[i] - b); });
      // 近い点は消す
      rep(j, (int)pts.size() - 1) if (abs(pts[j] - pts[j + 1]) < EPS) {
        pts.erase(pts.begin() + j);
        j--;
      }
      // 中点を足す
      int sz = (int)pts.size() - 1;
      rep(j, sz) pts.pb((pts[j] + pts[j + 1]) / 2.0);
      sort(all(pts), [&](P a, P b) { return abs(ps[i] - a) < abs(ps[i] - b); });
      swap(pts[1], pts.back());
      points.pb(pts);
    }
    // rep(i, n) dbg(i, points[i]);

    int ans = (n + 1) / 2;
    rep(mask, 1 << n) {
      int sz = __builtin_popcount(mask);
      if (sz >= ans)
        continue;

      for (const auto &pts : points)
        for (const P &p : pts) {
          bool ok = 0;
          rep(i, n) if (mask & 1 << i) {
            L l(p, ps[i]);
            G crs = {l[0], l[1]};

            // 辺と交差してたらダメ
            rep(j, n) {
              L e(ps[j], ps[(j + 1) % n]);
              if (intersectSS(l, e))
                goto NG;
            }

            // 外に出てたらダメ
            rep(j, n) if (ccw(l[0], ps[j], l[1]) == -2) crs.pb(ps[j]);
            sort(all(crs),
                 [&](P a, P b) { return abs(l[0] - a) < abs(l[0] - b); });
            rep(j, (int)crs.size() - 1) {
              if (contains(ps, (crs[j] + crs[j + 1]) / 2.0) == OUT) {
                /*
                dbg(crs[j], crs[j+1]);
                dbg((crs[j] + crs[j+1]) / 2.0);
                */
                goto NG;
              }
            }
            ok = 1;
            break;
          NG:;
            // dbg(p, i, ps[i]);
          }
          if (!ok)
            goto NEXT;
        }
      ans = min(ans, sz);
    NEXT:;
    }
    cout << ans << endl;
  }
  return 0;
}