2020牛客寒假算法基础集训营2——D.数三角【极角排序】(N^2*logN解法)

题目传送门


题目描述

牛牛得到了一个平面,这个平面上有 n n 个不重合的点,第 i i 个点的坐标为 ( x i , y i ) (x_i,y_i) .

牛牛想知道,这 n n 个点形成的三角形中,总共有多少个钝角三角形。


输入描述:

第一行,一个正整数 n n ,表示点数。

第二行至第 n + 1 n+1 行中,第 i + 1 i+1 行包含两个整数 x i , y i x_i,y_i ,表示第 i i 个点的坐标。

保证 1 n 500 1 0 4 x i , y i 1 0 4 1\leq n\leq 500,-10^4\leq x_i,y_i\leq 10^4
,任意两点不重合。


输出描述:

输出一行,一个整数表示答案。


输入

3
0 0
-1145 1
1 0

输出

1


题解

  • 官方题解是 N 3 N^3 枚举所有角,然后找钝角,显然题目压缩了数据范围。原题数据范围 2 e 3 2e3 ,这显然是不能承受的
  • 求出任意两点构成的向量,按照极角排序
  • 之后可以 二分 、也可以 t w o two p o i n t point ,显然 t w o two p o i n t point 更优雅一些 (更好写)
  • 总的复杂度是 O ( N 2 l o g N ) O(N^2*logN)

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;
}
发布了157 篇原创文章 · 获赞 99 · 访问量 9815

猜你喜欢

转载自blog.csdn.net/Q_1849805767/article/details/104200915