链接
http://www.lydsy.com/JudgeOnline/problem.php?id=1132
题解
我去年买了个表。————Popoqqq
这道题我调了一下午。
这样做,先枚举顶点,然后搞出
N−1
个向量,现在就成了求两两向量的叉积之和(前提是叉积为正数)。
那就先极角排序,然后两个指针扫描,两个指针的夹角时刻小于
π
,中间夹着的向量求个和,用最后一个向量和这些向量的和向量叉积即可,累加进答案。
要特别考虑头指针追上尾指针的情况,这个sb的地方让我调了半个下午。
还有这道题用
double
会被卡,要用
long double
,或者你也可以学
popoqqq
用
long long
。
最后一个蛋疼的地方:数据有一条链,这个用我的算法会死循环,要特判一下。
代码
//计算几何
#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cmath>
#define maxn 4000
#define eps 1e-8
#define real long double
using namespace std;
struct point{double x, y;}pt[maxn];
struct vec
{
double x, y, th;
void calc(){th=atan2(y,x);}
}v[maxn];
int nex[maxn], N, pre[maxn];
real S;
inline real operator*(vec v1, vec v2){return v1.x*v2.y-v2.x*v1.y;}
inline bool operator<(vec v1, vec v2){return v1.th<v2.th;}
real work(int num)
{
int i, tot=0, p;
real sx=0, sy=0, s=0;
for(i=num+1;i<=N;i++)
{
v[++tot]=(vec){pt[i].x-pt[num].x,pt[i].y-pt[num].y};
v[tot].calc();
}
sort(v+1,v+tot+1);
for(i=2;i<=tot;i++)if(v[i]*v[i-1]!=0)break;
if(i>tot)return 0.0;
for(i=1;i<tot;i++)nex[i]=i+1;nex[tot]=1;
for(i=2;i<=tot;i++)pre[i]=i-1;pre[1]=tot;
for(p=1;v[p]*v[1]>-eps;){sx+=v[p].x, sy+=v[p].y;p=pre[p];if(p==1)break;}p=nex[p];
for(i=1;;)
{
for(;v[p]*v[i]<0;p=nex[p])sx-=v[p].x, sy-=v[p].y;
s+=sx*v[i].y-v[i].x*sy;
i=nex[i], sx+=v[i].x, sy+=v[i].y;
if(i==p)
{
sx-=v[p].x, sy-=v[p].y, p=nex[p];
for(;v[p]*v[i]==0;p=nex[p])sx-=v[p].x, sy-=v[p].y;
}
if(i==1)break;
}
return s;
}
void init()
{
int i, x, y;
scanf("%d",&N);
for(i=1;i<=N;i++)scanf("%d%d",&x,&y),pt[i].x=x,pt[i].y=y;
}
int main()
{
int i;
init();
if(N<3){printf("0.0");return 0;}
for(i=1;i<=N-2;i++)S+=work(i);
printf("%.1Lf\n",S/2.0);
return 0;
}
本文介绍了一个计算几何问题的解决思路及实现代码。该问题涉及点的枚举、向量叉积计算、极角排序等步骤,并针对特殊情况进行了讨论。

被折叠的 条评论
为什么被折叠?



