您的位置:首页 > 其它

bzoj1132 [POI2008]Tro(叉积)

2017-12-06 22:23 429 查看

bzoj1132 [POI2008]Tro

原题地址http://www.lydsy.com/JudgeOnline/problem.php?id=1132

题意:

平面上有N个点. 求出所有以这N个点为顶点的三角形的面积和 N<=3000

数据范围

N在[3,3000] ,N个点的坐标值在[0,10000]

保留一位小数,误差不超过0.1

题解:

好题。

我想了两种做法,

第一种:考虑一般求多边形面积的方法。



S=S蓝1+S蓝2-S红

其实就是计算每条边的贡献。

对于x以右的点极角排序,

ab 这样的边贡献+1

(保存一个两两边贡献的后缀和)

x与a这样的点连边的贡献就(前面的点的个数-后面的点的个数)

正解:

考虑叉积到底是个什么。

x1y2-x2y1

如果a对于x的坐标(x1,y1),b对于x的坐标(x2,y2)

提个公因数,

x1贡献 ∑y2

y1贡献-∑x2

因为要用叉积算,要保证>0,于是让它有序就行。

先按x排序,枚举每个点,他之右的极角排序,然后存个前缀和算。

一个困扰我很久的点:

第一遍排序:
bool cmp1(const Poi &A,const Poi &B){return A.x<B.x;}


结果:WA

第一遍排序:
bool cmp1(const Poi &A,const Poi &B){return A.x<B.x||(A.x==B.x&&A.y<B.y);}


结果:AC

一组数据:

(10,1)(10,2)(10,3) ,(15,2)

正确答案是10.0

但对于第一种排序,显然它对于前三个点的顺序不作要求,

当顺序为:(10,2)(10,3) (10,1),(15,2)时,

答案为 5.0,错了!!!

而对称的(10,2)(10,1) (10,3),(15,2)

答案则是正确的 10.0

为什么?感谢Doggu非常耐心的答疑。

打印出过程发现,同样第一个数取(10,2),那么剩下三个点对于他的坐标分别为:

(5,0)(0,1)(0,-1)

第一种的极角排序:(0,-1)(0,1)(5,0)

正常的极角排序:(0,-1)(5,0)(0,1)

极角排序不对!!!

考虑到我们为了追求常数小,比较极角用的不是atan2,而是叉积:

bool cmp2(const Poi &A,const Poi &B){return A.x*B.y-B.x*A.y>0;}


那么对于(0,-1)和(0,1)他们的叉积为0,其实是互相小于的,一旦比较顺序不对,排序就不对。

因此必须按x为第一关键字,y为第二关键字排,才不会出现这种上下都有的情况。

下次用叉积也要小心了。

代码:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#define LL long long
using namespace std;
const int N=3005;
struct Poi
{
int x,y;
Poi(){}
Poi(int x,int y):x(x),y(y){}
}P
,v
;
Poi operator-(const Poi &A,const Poi &B){return Poi(A.x-B.x,A.y-B.y);}
bool cmp1(const Poi &A,const Poi &B){return A.x<B.x||(A.x==B.x&&A.y<B.y);}
bool cmp2(const Poi &A,const Poi &B){return A.x*B.y-B.x*A.y>0;}
int n;
LL ret=0;
void solve()
{
sort(P+1,P+n+1,cmp1);
for(int i=1;i<n-1;i++)
{
int cnt=0; LL sx=0,sy=0;
for(int j=i+1;j<=n;j++)
{
v[++cnt]=P[j]-P[i];
}
sort(v+1,v+cnt+1,cmp2);
for(int j=1;j<=cnt;j++)
{
ret-=1LL*v[j].x*sy;
ret+=1LL*v[j].y*sx;
sx+=v[j].x; sy+=v[j].y;
}
}
printf("%lld.%lld\n",ret>>1,5LL*(ret&1));
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d%d",&P[i].x,&P[i].y);
solve();
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: