bzoj1132: [POI2008]Tro

本文介绍了一个计算几何问题的解决思路及实现代码。该问题涉及点的枚举、向量叉积计算、极角排序等步骤,并针对特殊情况进行了讨论。

链接

  http://www.lydsy.com/JudgeOnline/problem.php?id=1132

题解

我去年买了个表。————Popoqqq

  这道题我调了一下午。
  这样做,先枚举顶点,然后搞出 N1 个向量,现在就成了求两两向量的叉积之和(前提是叉积为正数)。
  那就先极角排序,然后两个指针扫描,两个指针的夹角时刻小于 π ,中间夹着的向量求个和,用最后一个向量和这些向量的和向量叉积即可,累加进答案。
  要特别考虑头指针追上尾指针的情况,这个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;
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值