Codeforces-1284E:New Year and Castle Construction(计算几何)

E. New Year and Castle Construction
time limit per test 3 seconds
memory limit per test 1024 megabytes
input standard input
output standard output
Kiwon’s favorite video game is now holding a new year event to motivate the users! The game is about building and defending a castle, which led Kiwon to think about the following puzzle.

In a 2-dimension plane, you have a set s = { ( x 1 , y 1 ) , ( x 2 , y 2 ) , … , ( x n , y n ) } s=\{(x_1,y_1),(x_2,y_2),…,(x_n,y_n)\} s={(x1,y1),(x2,y2),,(xn,yn)} consisting of n distinct points. In the set s, no three distinct points lie on a single line. For a point p ∈ s p∈s ps, we can protect this point by building a castle. A castle is a simple quadrilateral (polygon with 4 vertices) that strictly encloses the point p (i.e. the point p is strictly inside a quadrilateral).

Kiwon is interested in the number of 4-point subsets of s that can be used to build a castle protecting p. Note that, if a single subset can be connected in more than one way to enclose a point, it is counted only once.

Let f ( p ) f(p) f(p) be the number of 4-point subsets that can enclose the point p. Please compute the sum of f ( p ) f(p) f(p) for all points p ∈ s p∈s ps.

Input
The first line contains a single integer n ( 5 ≤ n ≤ 2500 ) n (5≤n≤2500) n(5n2500).

In the next n lines, two integers x i x_i xi and y i y_i yi ( − 1 0 9 ≤ x i , y i ≤ 1 0 9 ) (−10^9≤x_i,y_i≤10^9) (109xi,yi109) denoting the position of points are given.

It is guaranteed that all points are distinct, and there are no three collinear points.

Output
Print the sum of f ( p ) f(p) f(p) for all points p ∈ s p∈s ps.

Examples
input
5
-1 0
1 0
-10 -1
10 -1
0 3
output
2
input
8
0 1
1 2
2 2
1 3
0 -1
-1 -2
-2 -2
-1 -3
output
40
input
10
588634631 265299215
-257682751 342279997
527377039 82412729
145077145 702473706
276067232 912883502
822614418 -514698233
280281434 -41461635
65985059 -827653144
188538640 592896147
-857422304 -529223472
output
213

思路:枚举每一个点作为被包围的点,假设被包围的点为 P P P,那么我们需要求出剩下的 n − 1 n-1 n1个点中,有多少方案选4个点使其构成的四边形能包围 P P P点,但这样很难求。
考虑求出有多少种方案使得四边形不能够包围住点 P P P,那么只需减去这些方案即可。设四边形的四点分别为 S S S S 1 S_1 S1 S 2 S_2 S2 S 3 S_3 S3。那么当点 S 1 S_1 S1 S 2 S_2 S2 S 3 S_3 S3都位于直线 P S PS PS的同一边时,这个四边形必定不能包围住点 P P P
那么将 n − 1 n-1 n1个点按照极角排序,依次枚举点 S S S,利用滑动窗口,求出位于 P S PS PS同一边的点个数即可。

PS:利用atan2精度可能不够。利用叉积进行极角排序的方法是错误的,样列3过不了。

#include
using namespace std;
const int MAX=2e5+10;
const int MOD=1e9+7;
typedef long long ll;
struct Point{ll x,y;}p[MAX];
Point operator-(Point A,Point B){return (Point){A.x-B.x,A.y-B.y};}
ll operator^(Point A,Point B){return A.x*B.y-A.y*B.x;}
vector<Point>v;
int which(const Point&A)
{
    if(A.x>0&&A.y>=0)return 1;
    if(A.x<=0&&A.y>0)return 2;
    if(A.x<0&&A.y<=0)return 3;
    if(A.x>=0&&A.y<0)return 4;
}
int cmp(const Point&A,const Point&B)
{
    if(which(A)!=which(B))return which(A)<which(B);
    return (A^B)>0;
}
int main()
{
    ll n;
    cin>>n;
    for(int i=1;i<=n;i++)scanf("%lld%lld",&p[i].x,&p[i].y);
    ll ans=0;
    for(int i=1;i<=n;i++)
    {
        v.clear();
        for(int j=1;j<=n;j++)if(i!=j)v.push_back(p[j]-p[i]);
        sort(v.begin(),v.end(),cmp);
        ll k=0;
        for(int j=0;j<n-1;j++)
        {
            while(k-j<n-1&&(v[j]^v[k%(n-1)])>=0)k++;
            ans-=(k-j-1)*(k-j-2)*(k-j-3)/6;
        }
        ans+=(n-1)*(n-2)*(n-3)*(n-4)/24;
    }
    cout<<ans<<endl;
    return 0;
}

你可能感兴趣的:(计算几何)