bzoj1132[POI2008]Tro 计算几何

1132: [POI2008]Tro

Time Limit: 20 Sec  Memory Limit: 162 MB
Submit: 1722  Solved: 575
[Submit][Status][Discuss]

Description

平面上有N个点. 求出所有以这N个点为顶点的三角形的面积和 N<=3000

Input

第一行给出数字N,N在[3,3000] 下面N行给出N个点的坐标,其值在[0,10000]

Output

保留一位小数,误差不超过0.1

Sample Input

5
0 0
1 2
0 2
1 0
1 1

Sample Output

7.0

HINT

 

看见题一眼知道怎么做,然后排序挂了,调了好久
计算面积可以通过叉积前缀的形式来求和,但是叉积求出的是有向面积,所以必须处理abs的问题
怎么处理呢?让所有的叉积都>0是最好的处理方法,可以通过排序来实现

枚举点i,再枚举i之前的点与i构成i-1个向量,对这些向量排序使得标号大的向量叉积标号小的一定>0,并动态统计这些向量的前缀和即可

但是有可能出现问题:
如果一开始点是无序的,很混乱,那么可能会出现以这种情况
for example
4
-5 3
6 -3
4 -6
-2 2

辣么,在处理最后一个点的时候,会出现排序紊乱的情况
我想了一下,发现了原因:(-5,3)与(-2,2) (4,-6)与(2,2) 这两条线段构成的角,从(-4,6)逆时针转上去,形成了一个钝角。。
于是我们需要把每次枚举的i点设置为原点,使得处理它时,所有要被计算的点在同一象限
说起来很麻烦,实际就是按照横纵坐标排个序

其实这个题还挺水的。

 1 #include<bits/stdc++.h>
 2 #define N 3005
 3 #define ll long long
 4 using namespace std;
 5 int n,tp;ll ans;
 6 struct point{
 7     int x,y;
 8     point operator - (const point &b)const{return (point){x-b.x,y-b.y};}
 9     point operator + (const point &b)const{return (point){x+b.x,y+b.y};}
10 }a[N],q[N];
11 ll crs(point a,point b){return (ll)a.x*b.y-(ll)a.y*b.x;}
12 bool cmp1(point x,point y){return x.x==y.x?x.y<y.y:x.x<y.x;}
13 bool cmp2(point x,point y){return crs(x,y)<0;}
14 int main(){
15     scanf("%d",&n);
16     for(int i=1;i<=n;i++)
17     scanf("%d%d",&a[i].x,&a[i].y);
18     sort(a+1,a+1+n,cmp1);
19     for(int i=1;i<=n;i++){
20         point t;t.x=t.y=0;tp=0;
21         for(int j=1;j<i;j++)
22         q[++tp]=a[j]-a[i];
23         sort(q+1,q+1+tp,cmp2);
24         for(int j=1;j<i;j++){
25             ans+=crs(q[j],t);
26             t=t+q[j];
27         }
28     }
29     if(ans&1)printf("%lld.5
",ans>>1);
30     else printf("%lld.0
",ans>>1);
31     return 0;
32 }
原文地址:https://www.cnblogs.com/wsy01/p/8179509.html