1. 程式人生 > >5784 How Many Triangles 極角排序

5784 How Many Triangles 極角排序

題意:給出n個不重合的點,問能形成多少個不同的銳角三角形。

思路:統計出所有的銳角,直角,鈍角的數量,假設分別為A,B,C,由於一個鈍角或者直角三角形中也包含兩個銳角,因此答案為(A - 2 * (B + C)) / 3.

下面考慮如何快速求解:

列舉每一個頂點,算出所有向量,極角排序後再列舉每一個向量,用類似尺取的方法找到逆時針方向能和該向量形成最大銳角和鈍角的向量的位置,計算對答案的貢獻,注意每次開始要跳過所有同向的向量。

幾種極角排序方法:點選開啟連結

程式碼:

#include<bits/stdc++.h>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
typedef pair<int,int> P;
const int MAXN = 2010;
struct point{
	ll x, y;
	point(ll _x = 0, ll _y = 0) : x(_x), y(_y) {}
	point operator - (const point &a) const
	{
		return point(x - a.x, y - a.y);
	}
	ll operator * (const point &a) const
	{
		return x * a.y - y * a.x;
	}
	ll operator ^ (const point &a) const
	{
		return x * a.x + y * a.y;
	}
	bool sign() const
	{
		return y > 0 || (y == 0 && x > 0);
	}
	bool operator < (const point &a) const
	{
		if(sign() == a.sign()) return (*this) * a > 0;
		return sign() > a.sign();
	}
}p[MAXN], tmp[MAXN << 1];
int main()
{
	int n;
	while(cin >> n)
	{
		int ans = 0;
		for(int i = 0; i < n; i++)
		scanf("%lld %lld", &p[i].x, &p[i].y);
		for(int i = 0; i < n; i++)
		{
			int cnt = 0;
			for(int j = 0; j < n; j++)
			if(i != j)
			tmp[cnt++] = p[j] - p[i];
			sort(tmp, tmp + cnt);
			for(int j = 0; j < cnt; j++) tmp[j + cnt] = tmp[j];
			int id1, id2, id3;//同向向量、銳角、鈍角對應的最大下標 
			id1 = id2 = id3 = 0; 
			for(int j = 0; j < cnt; j++)
			{
				while(id1 < cnt * 2 && (tmp[j] * tmp[id1]) == 0 && (tmp[j] ^ tmp[id1]) > 0) id1++;
				id2 = max(id2, id1);
				while(id2 < cnt * 2 && (tmp[j] * tmp[id2]) > 0 && (tmp[j] ^ tmp[id2]) > 0) id2++;
				id3 = max(id3, id2);
				while(id3 < cnt * 2 && (tmp[j] * tmp[id3]) > 0 && (tmp[j] ^ tmp[id3]) < 0) id3++;
				ans += id2 - id1;
				ans -= 2 * (id3 - id2);
			}
		}
		printf("%d\n", ans / 3);
	}
 	return 0;
}