1. 程式人生 > >How Many Triangles (極角排序 + 尺取法)

How Many Triangles (極角排序 + 尺取法)

  題意:二維平面與有很多個點,然後求構成銳角三角形的個數。

  思路:對於每一個三角形我們知道存在至少2個銳角,只要有一個鈍角就不行了,所以我們的想法就是列舉所有夾角的狀態,然後得知情況,確定用總個數減去-成線或者成鈍角的數量/2(除以2是因為計算過程中重複了)。那麼應該如何列舉?我們列舉夾角的頂點然後就出其他點的極角,排序,然後尺取法左端點表示與當前點為銳角的個數,右端點表示銳角+鈍角,過程中相減可以得到銳角數量。

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
const int maxn = 2000
+ 7; struct P{ ll x, y; P() {} P(ll x, ll y): x(x), y(y) {} P operator + (P p) { return P(x + p.x, y + p.y); } void read() { scanf("%lld%lld", &x, &y); } P operator - (P p) { return P(x - p.x, y - p.y); } ll dot(P p) {//點積 return
x * p.x + y * p.y; } ll det(P p) {//叉積 return x * p.y - y * p.x; } bool operator < (const P &p) const{ if(y * p.y <= 0) { if(y > 0 || p.y > 0) return y < p.y; if(y == 0 && p.y == 0)return x < p.x; } return
x * p.y - y * p.x > 0; } }p[maxn], q[maxn << 1]; int main(){ int n;while(~scanf("%d", &n)) { ll ans = 1ll * n * (n - 1) * (n - 2) / 6; ll line = 0; for(int i = 0; i < n; i ++) p[i].read(); for(int i = 0; i < n; i ++) { int tot = 0; for(int j = 0; j < n; j ++) if(i != j) q[tot ++] = p[j] - p[i]; ll subtrat = 0; sort(q, q + tot); for(int j = 0; j < tot; j ++) q[j + tot] = q[j]; for(int j = 1; j < tot; j ++) { if(q[j - 1].det(q[j]) == 0 && q[j - 1].dot(q[j]) > 0) subtrat ++; else subtrat = 0; line += subtrat; } int l = 0, r = 0; for(int j = 0; j < tot; j ++) { while(l <= j || (l < j + tot && q[l].det(q[j]) < 0 && q[j].dot(q[l]) > 0)) l ++; while(r <= j || (r < j + tot && q[r].det(q[j]) < 0)) r ++; ans -= r - l; } } printf("%lld\n",ans - line/2); } return 0; }