题目描述
传送门
题目大意:平面上有N个点. 求出所有以这N个点为顶点的三角形的面积和
题解
枚举每个点作为原点,然后得到一对起点在原点的向量,两个夹角小于180的向量叉积的1/2就是一个合法的三角形的面积。
那么我们将所有的向量按照极角序排序,用two pointer扫一下,因为叉积满足分配率,所以我们可以维护对于每个向量可以与他做叉积得到正数的向量和,最后计算一下面积。
但是实际可以不用这么麻烦,我们现将点按照x为第一关键字,y为第二关键字排序。对于每个点我们只考虑他右侧的点,那么他与他右侧的点形成的向量一定都是夹角小于等于180度的,将这些向量按照极角序排序,对于每个向量叉积上从这个向量开始的后缀和即可。
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define N 3010
#define LL long long
using namespace std;
int n,cnt; bool pd[N];
struct data{
LL x,y;
data(LL X=0,LL Y=0) {
x=X,y=Y;
}
}p[N];
data operator -(data a,data b){
return data(a.x-b.x,a.y-b.y);
}
data operator +(data a,data b){
return data(a.x+b.x,a.y+b.y);
}
LL operator *(data a,data b){
return a.x*b.y-a.y*b.x;
}
struct line{
data p,v; double ang;
line(data a=data(),data b=data()){
p=a; v=b-a; ang=atan2(v.y,v.x);
}
bool operator <(const line &a)const {
return ang<a.ang;
}
}l[N];
int main()
{
freopen("a.in","r",stdin);
freopen("my.out","w",stdout);
scanf("%d",&n); LL ans=0;
for (int i=1;i<=n;i++) scanf("%lld%lld",&p[i].x,&p[i].y);
for (int now=1;now<=n;now++) {
cnt=0;
for (int i=1;i<=n;i++) {
if (i==now) continue;
cnt++;
l[cnt]=line(p[now],p[i]);
if(l[cnt].v.x==0&&l[cnt].v.y==0) cnt--;
}
sort(l+1,l+cnt+1);
memset(pd,0,sizeof(pd));
int tail=1; data sum; sum.x=l[1].v.x; sum.y=l[1].v.y; pd[1]=1;
for (int i=1;i<=cnt;i++) {
while (l[i].v*l[tail%cnt+1].v>0&&!pd[tail%cnt+1]||l[i].v*l[tail%cnt+1].v==0&&tail%cnt+1>=i&&!pd[tail%cnt+1]){
tail=tail%cnt+1; pd[tail]=1;
sum=sum+l[tail].v;
}
ans+=l[i].v*sum;
sum=sum-l[i].v; pd[i]=0;
}
}
if (ans%6) printf("%lld.5\n",ans/6);
else printf("%lld.0\n",ans/6);
}