Description
Solution
考虑平面相交线段对数等于平面凸四边形数(相交线段相当于对角线)。
平面凸四边形个数转化为总数减去凹四边形数。
凹四边形数相当于一个三角形中包含了一个点。
枚举被包含的点,计算包含它的三角形比较麻烦,统计不包含它的三角形。
极角排序后,若两个向量 i , j i,j i,j之间的夹角小于 π \pi π,那么 i + 1 i+1 i+1到 j j j的向量任意选出两个与 i i i组合一定能组成不包含当前点的三角形,two-pointers统计即可。
#include <bits/stdc++.h>
using namespace std;
typedef long long lint;
const int maxn = 705;
const double pi = acos(-1);
int n;
int x[maxn], y[maxn], tot;
lint ans;
struct point
{
int x, y;
double angle;
bool operator < (const point &a) const {
return angle < a.angle;
}
} p[maxn * 2];
inline int gi()
{
char c = getchar(); bool f = 1;
while (c != '-' && (c < '0' || c > '9')) c = getchar();
if (c == '-') c = getchar(), f = 0;
int sum = 0;
while ('0' <= c && c <= '9') sum = sum * 10 + c - 48, c = getchar();
return f ? sum : -sum;
}
lint solve(int k)
{
lint res = (lint)(n - 1) * (n - 2) * (n - 3) / 6;
tot = 0;
for (int i = 1; i <= n; ++i)
if (i != k) {
p[++tot] = (point) {x[i] - x[k], y[i] - y[k]}; p[tot].angle = atan2(p[tot].y, p[tot].x);
p[++tot] = (point) {x[i] - x[k], y[i] - y[k]}; p[tot].angle = p[tot - 1].angle + pi * 2;
}
sort(p + 1, p + tot + 1);
for (int i = 1, j = 0; i < n; ++i) {
while (p[j + 1].angle - p[i].angle <= pi) ++j;
if (j - i >= 2) res -= (j - i) * (j - i - 1) / 2;
}
return res;
}
int main()
{
freopen("convex.in", "r", stdin);
freopen("convex.out", "w", stdout);
int T = gi();
while (T--) {
n = gi();
for (int i = 1; i <= n; ++i) x[i] = gi(), y[i] = gi();
ans = (lint)n * (n - 1) * (n - 2) * (n - 3) / 24;
for (int i = 1; i <= n; ++i) ans -= solve(i);
printf("%lld\n", ans);
}
return 0;
}

本文介绍了一种算法,用于计算平面上凸四边形的数量及线段间的相交对数。通过将问题转化为总数减去凹四边形数,再利用极角排序和two-pointers技巧,高效统计不包含特定点的三角形数量。
11万+

被折叠的 条评论
为什么被折叠?



