2016hdu多校賽第5場(hdu5784)

題意

平面上給2000個點,問有多少個銳角三角形。

解法

官方題解:

數一數銳角的數量A和直角+鈍角的數量B,那麼答案就是(A-2B)/3。 暴力算的話是O(n^3)的。使用極角排序+two pointers就可以做到O(n^2logn)這邊鈍角指代範圍在90度到180度之間的角(不包括90和180)。

對於每個點,以他爲中心進行一次極角排序。然後尺取找到鈍角和銳角數目。

自己寫了一下試試,發現尺取的地方比較噁心。

代碼

#include<bits/stdc++.h>

using namespace std;

const int SIZE = 2005;
typedef long long ll;

struct point2
{
    ll x, y;
    point2(ll xx = 0, ll yy = 0)
    {
        x = xx; y = yy;
    }
    point2 operator + (const point2 &a)const
    {
        return point2(x + a.x, y + a.y);
    }
    point2 operator - (const point2 &a)const
    {
        return point2(x - a.x, y - a.y);
    }
    ll operator * (const point2 &a)const
    {
        return x*a.x + y*a.y;
    }
    ll operator ^ (const point2 &a)const
    {
        return x*a.y - y*a.x;
    }
    bool operator < (const point2 &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 ((*this)^a) > 0;
    }
} A[SIZE];

int main() {
    int n;
    vector<point2> v;
    while(~scanf("%d",&n)){
        for(int i = 0; i < n; i++) {
            int a, b;
            scanf("%d%d",&a,&b);
            A[i] = point2(a, b); //這樣其實沒有寫成員函數賦值快我猜
        }
        ll rui = 0, dz = 0;
        for(int ii = 0; ii < n; ii++) {
            v.clear();
            for(int j = 0; j < n; j++) {
                if(ii == j) continue;
                v.emplace_back(A[j] - A[ii]); //直接在尾部構造,比較快
            }
            sort(v.begin(), v.end());
            v.insert(v.end(), v.begin(), v.end());
            for(int i = 0, j = 0, k = 0, r = 0; i < n - 1; i++) {
                while(j < i + n - 1 && !(v[i]^v[j]) && (v[i]*v[j]) > 0 ) j++;//0度角的結束位置
                k = max(k, j);
                while(k < i + n - 1 && (v[i]^v[k]) > 0 && (v[i]*v[k]) > 0) k++;//銳角的結束位置
                r = max(r, k);
                while(r < i + n - 1 && (v[i]^v[r]) > 0) r++;//鈍角的結束位置,對於大於180的角,當枚舉到另一條邊的時候會計算到這個情況
                rui += k - j;
                dz += r - k;
            }
        }
        //cout << rui << " "<<dz<<endl;
        printf("%I64d\n",(rui - 2*dz)/3);
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章