题意:
给出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; }
时间: 2024-10-08 04:11:47