bzoj-1132 Tro

来源:互联网 发布:图书馆管理系统数据库 编辑:程序博客网 时间:2024/05/16 01:35

题意:

给出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 3100using 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;elset[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;}




0 0