VK Cup 2017 - Round 1 F :F. Bear and Isomorphic Points(半平面交)

本文介绍了一种解决半平面交问题的有效算法,并通过实例详细解释了如何筛选关键直线并进行计算,最终求得所需区域面积。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

传送门

题解:
一般这种半平面交题都是舍去一些直线然后做,这题也是类似。 可以用归纳法证明每个点只需要和极角序下他的下一个点和最后一个点(满足1在其同一侧)连线即可。

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef double LD;
inline int rd() {
    char ch=getchar(); int i=0,f=1;
    while(!isdigit(ch)) {if(ch=='-')f=-1; ch=getchar();}
    while(isdigit(ch)) {i=(i<<1)+(i<<3)+ch-'0'; ch=getchar();}
    return i*f;
}
const int N=2e5+50;
const LD eps=1e-11;
const LD PI=acos(-1.0);
const LD PI2=PI*2;
inline LD fix(LD x) {
    while(x<-PI) x+=PI2;
    while(x>PI) x-=PI2;
    return x;
}
inline int sgn(LD x) {return (x>eps)-(x<-eps);}
inline int cmp(LD x,LD y) {return sgn(x-y);}
LD a[N*2];
int n,tot;
inline int nxt(int i) {return (i==n)?2:i+1;}
struct P {
    LD x,y; LD slope;
    P(LD x=0,LD y=0):x(x),y(y){}
    friend inline P operator -(const P &a,const P &b) {return P(a.x-b.x,a.y-b.y);}
    friend inline LD operator *(const P &a,const P &b) {return a.x*b.y-a.y*b.x;}
    friend inline bool operator <(const P &a,const P &b) {return a.slope<b.slope;}
    friend inline bool left(const P &a,const P &b,const P &c) {return sgn((c-b)*(a-b))>=0;}
}p[N];
struct L {
    P a,b; LD slope;
    L() {}
    L(P _a,P _b) {a=_a, b=_b; slope=atan2(b.y-a.y,b.x-a.x);}
    friend inline bool operator <(const L &a,const L &b) {
        if(cmp(a.slope,b.slope)) return a.slope<b.slope;
        return sgn((a.b-b.a)*(a.a-b.a))<0;
    }
    friend inline P inter(const L &a,const L &b) {
        LD k1=(a.b-b.a)*(a.a-b.a);
        LD k2=(a.a-b.b)*(a.b-b.b);
        LD t=k1/(k1+k2);
        return P(b.a.x+(b.b.x-b.a.x)*t,b.a.y+(b.b.y-b.a.y)*t);
    }
}l[N*2];
inline bool judge(const L &a,const L &b,const L &c) {
    P o=inter(a,b);
    return sgn((c.a-o)*(c.b-o))<=0;
}
inline LD hpi() {
    sort(l+1,l+tot+1); n=0;
    for(int i=1;i<=tot;i++) {
        if(i==1 || cmp(l[i].slope,l[i-1].slope)) ++n;
        l[n]=l[i];
    }
    int L=1,R=2;
    for(int i=3;i<=n;i++) {
        while(L<R && judge(l[R-1],l[R],l[i])) --R;
        while(L<R && judge(l[L+1],l[L],l[i])) ++L;
        l[++R]=l[i];
    }
    while(L<R+1 && judge(l[L+1],l[L],l[R])) ++L;
    while(L<R+1 && judge(l[R],l[R-1],l[L])) --R;
    n=0; l[R+1]=l[L]; 
    for(int i=L;i<=R;i++) p[++n]=inter(l[i],l[i+1]);
    p[n+1]=p[1]; LD ans=0;
    for(int i=1;i<=n;i++) ans+=p[i]*p[i+1];
    return fabs(ans)/2.0;
}
inline void solve() {
    n=rd(); tot=0;
    for(int i=1;i<=n;i++) p[i].x=rd(), p[i].y=rd();
    for(int i=2;i<=n;i++) 
        p[i].slope=fix(atan2(p[i].y-p[1].y,p[i].x-p[1].x)), a[++tot]=p[i].slope, a[++tot]=fix(p[i].slope+PI);
    sort(p+2,p+n+1); sort(a+1,a+tot+1);
    for(int i=1;i<tot;i++) if(cmp(a[i],a[i+1])==0) {printf("%.10f\n",0); return;}
    tot=0;
    for(int p1=2,p2=3;p1<=n;) {
        if(!left(p[1],p[p1],p[nxt(p1)])) {++p1; p2=nxt(p1); continue;}
        l[++tot]=L(p[p1],p[nxt(p1)]);
        while(nxt(p2)!=p1 && left(p[1],p[p1],p[nxt(p2)])) p2=nxt(p2);
        l[++tot]=L(p[p1],p[p2]); ++p1; 
    }
    l[++tot]=L(P(1e6,1e6),P(-1e6,1e6));
    l[++tot]=L(P(-1e6,1e6),P(-1e6,-1e6));
    l[++tot]=L(P(-1e6,-1e6),P(1e6,-1e6));
    l[++tot]=L(P(1e6,-1e6),P(1e6,1e6));
    printf("%.10f\n",(double)hpi());
}
int main() {
    for(int T=rd();T;T--) solve();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值