传送门
求凸四边形的个数
转化成总数减去凹四边形的个数
凹四边形一定是一个三角形中间包含的另外一个点
那么枚举被包含的点,其它的对于这个点极角排序
被包含不好算,算总数减去不被包含的
枚举三角形的一个顶点,那么另外一个顶点和这个顶点关于枚举的被包含的点的角度不超过
π
\pi
π
那么直接
t
w
o
−
p
o
i
n
t
e
r
s
two-pointers
two−pointers 统计即可
# include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn(2005);
const double eps(1e-9);
const double pi(acos(-1));
int n, test, tot;
ll ans, ret;
struct Point {
int x, y;
double angle;
inline bool operator <(Point b) const {
return angle - eps < b.angle;
}
} a[maxn], b[maxn];
inline ll Calc(int p) {
register int i, j;
ret = (ll)(n - 1) * (n - 2) * (n - 3) / 6, tot = 0;
for (i = 1; i <= n; ++i)
if (i ^ p) {
++tot, b[tot].x = a[i].x - a[p].x, b[tot].y = a[i].y - a[p].y;
b[tot].angle = atan2(b[tot].y, b[tot].x);
b[tot + n - 1].angle = b[tot].angle + pi * 2;
}
tot += n - 1, sort(b + 1, b + tot + 1);
for (i = 1, j = 1; i < n; ++i) {
while (j < i + n - 1 && b[j].angle - b[i].angle - eps < pi) ++j;
if (j - i - 1 >= 2) ret -= (ll)(j - i - 1) * (j - i - 2) / 2;
}
return ret;
}
int main() {
register int i;
scanf("%d", &test);
while (test) {
scanf("%d", &n), --test;
for (i = 1; i <= n; ++i) scanf("%d%d", &a[i].x, &a[i].y);
ans = (ll)n * (n - 1) * (n - 2) * (n - 3) / 24;
for (i = 1; i <= n; ++i) ans -= Calc(i);
printf("%lld\n", ans);
}
return 0;
}