bzoj1132[POI2008]Tro 计算几何
1132: [POI2008]Tro
Time Limit: 20 Sec Memory Limit: 162 MBSubmit: 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
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\n",ans>>1); 30 else printf("%lld.0\n",ans>>1); 31 return 0; 32 }
If you live in the echo,
your heart never beats as loud.
如果你生活在回声里,
你的心跳声永远不会轰鸣作响。