题意:
给出n个点,求这n个点组成的所有三角形的面积和;
n<=3000;
题解:
这道题O(n^3)枚举三角形时间复杂度是无法承受的;
所以考虑枚举一条边,多个三角形一起来计算,复杂度在O(n^2)的级别;
求三角形面积可以底乘高的面积公式,也可以上叉积;
而叉积的方法则是化简叉积的式子,可以把点的坐标提出来,加和一起运算;如果采用底乘高的方法,求出所有的点到直线的距离之和,也是可以O(1)得到当前的解的;
但是求距离之和这一步必然是O(n)的,也难以转移到下一个底上去;
但是叉积求得的是有向面积,这东西卡了我半天;
实际上实现是这样的:
枚举第一个点,取第一个点右上方的点集,将点集按与第一个点的斜率大小排序,然后枚举第二个点求解;
这样每个面积只求了一遍,而且因为斜率有序,所以所有三角形都是正的面积了;
因为排了序,所以时间复杂度O(n^2 logn);
(我居然因为保留两位小数WA了一晚上!!)
代码:
#include<math.h>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N 3100
using namespace std;
typedef long long ll;
struct Point
{
ll x,y;
double slope;
friend bool operator <(Point a,Point b)
{
if(a.x==b.x)
return a.y<b.y;
return a.x<b.x;
}
friend Point operator -(Point a,Point b)
{
return (Point){a.x-b.x,a.y-b.y};
}
friend int operator *(Point a,Point b)
{
return a.x*b.y-a.y*b.x;
}
}a[N],t[N],O;
bool cmp(Point a,Point b)
{
return a.slope>b.slope;
}
int main()
{
int n,m,i,j,k;
ll ans,sx,sy,tx,ty;
scanf("%d",&n);
for(i=1,sx=sy=0;i<=n;i++)
{
scanf("%d%d",&a[i].x,&a[i].y);
sx+=a[i].x,sy+=a[i].y;
}
sort(a+1,a+1+n);
for(i=1,ans=0;i<=n;i++)
{
sx-=a[i].x,sy-=a[i].y;
tx=sx,ty=sy;
O=a[i];
memcpy(t+i+1,a+i+1,sizeof(Point)*(n-i));
for(j=i+1;j<=n;j++)
{
if(t[j].x==O.x)
t[j].slope=1e10;
else
t[j].slope=(double)(t[j].y-O.y)/(t[j].x-O.x);
}
sort(t+i+1,t+n+1,cmp);
for(j=i+1;j<n;j++)
{
Point v=t[j]-a[i];
tx-=t[j].x,ty-=t[j].y;
ans+=tx*v.y-ty*v.x+(n-j)*(a[i].y*v.x-a[i].x*v.y);
}
}
printf("%lld.%d",ans>>1,ans&1?5:0);
return 0;
}