题目描述
牛牛得到了一个平面,这个平面上有 个不重合的点,第 个点的坐标为 .
牛牛想知道,这 个点形成的三角形中,总共有多少个钝角三角形。
输入描述:
第一行,一个正整数 ,表示点数。
第二行至第 行中,第 行包含两个整数 ,表示第 个点的坐标。
保证
,任意两点不重合。
输出描述:
输出一行,一个整数表示答案。
输入
3
0 0
-1145 1
1 0
输出
1
题解
- 官方题解是 枚举所有角,然后找钝角,显然题目压缩了数据范围。原题数据范围 ,这显然是不能承受的
- 求出任意两点构成的向量,按照极角排序
- 之后可以
、也可以
,显然
更优雅一些
(更好写) - 总的复杂度是
AC-Code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 500 + 5;
typedef struct Point {
ll x, y;
Point() {}
Point(ll x, ll y) : x(x), y(y) {}
Point operator + (Point p) { return Point(x + p.x, y + p.y); }
Point operator - (Point p) { return Point(x - p.x, y - p.y); }
ll dot(Point p) { return x * p.x + y * p.y; } // 点积(钝角<0;直角==0;锐角>0)
ll det(Point p) { return x * p.y - y * p.x; } // 叉积
bool operator < (const Point& a) const { // 极角升序
if (y * a.y <= 0) {
if (y > 0 || a.y > 0) return y > a.y;
if (y == 0 && a.y == 0) return x > a.x;
}
return x * a.y - y * a.x > 0;
}
}Vctor;
Point node[maxn];
Vctor vct[maxn * maxn];
int main(void)
{
int n; while (cin >> n) {
for (int i = 0; i < n; ++i)
cin >> node[i].x >> node[i].y;
ll res = 0;
for (int i = 0; i < n; ++i) {
ll tot = 0;
for (int j = 0; j < n; ++j) {
if (i == j) continue;
vct[tot++] = node[j] - node[i];
}
sort(vct, vct + tot);
for (int j = 0; j < tot; ++j) vct[j + tot] = vct[j]; /* 3、4象限按照环类似的处理方式 */
ll cnt1 = 0, cnt2 = 0;
for (int j = 0; j < tot; ++j) {
/*cnt在j左边*/ /* 3、4象限 */
while (cnt1 <= j || (cnt1 < j + tot && vct[cnt1].det(vct[j]) < 0) && vct[j].dot(vct[cnt1]) >= 0/*锐角和直角*/) cnt1++;//左边锐角和直角个数(左边最大的非钝角)
while (cnt2 <= j || (cnt1 < j + tot && vct[cnt2].det(vct[j]) < 0)) cnt2++;//左边所有角个数(左边最大的角)
res += cnt2 - cnt1;
}
}
cout << res << endl;
}
return 0;
}