洛谷P4250 [SCOI2015]小凸想跑步(半平面交)

题面

传送门

题解

\(p\)点坐标为\(x_p,y_p\),那么根据叉积可以算出它与\((i,i+1)\)构成的三角形的面积

为了保证\(p\)\((0,1)\)构成的面积最小,就相当于它比其它所有的三角形构成的面积都要小。如果\(p\)\((0,1)\)构成的面积比\((i,i+1)\)小,代入叉积计算公式,有

\[(y_0-y_1-y_i+y_{i+1})x_p+(x_1-x_0-x_{i+1}+x_i)y_p+(x_0y_1-x_1y_0-x_iy_{i+1}+x_{i+1}y_i) < 0\]

然后我们知道对于形如\(Ax+By+C<0\)的线性规划,向量\((-B,A)\)代表的就是这个线性规划的半平面

直接半平面交求解就行了

//minamoto
#include<bits/stdc++.h>
#define R register
#define inline __attribute__((always_inline))
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
using namespace std;
char buf[1<<21],*p1=buf,*p2=buf;
inline char getc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
int read(){
    R int res,f=1;R char ch;
    while((ch=getc())>'9'||ch<'0')(ch=='-')&&(f=-1);
    for(res=ch-'0';(ch=getc())>='0'&&ch<='9';res=res*10+ch-'0');
    return res*f;
}
char sr[1<<21],z[20];int C=-1,Z=0;
inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;}
void print(R int x){
    if(C>1<<20)Ot();if(x<0)sr[++C]='-',x=-x;
    while(z[++Z]=x%10+48,x/=10);
    while(sr[++C]=z[Z],--Z);sr[++C]='\n';
}
const int N=2e5+5;const double eps=1e-10;
inline int sgn(R double x){return x<-eps?-1:x>eps;}
inline double abs(R double x){return x<-eps?-x:x;}
struct node{
    double x,y;
    inline node(){}
    inline node(R double xx,R double yy):x(xx),y(yy){}
    inline node operator +(const node &b)const{return node(x+b.x,y+b.y);}
    inline node operator -(const node &b)const{return node(x-b.x,y-b.y);}
    inline double operator *(const node &b)const{return x*b.y-y*b.x;}
    inline node operator ^(const double &b)const{return node(x*b,y*b);}
}p[N],s[N];
struct Line{
    node p,v;double ang;
    inline Line(){}
    inline Line(R node pp,R node vv):p(pp),v(vv){ang=atan2(v.y,v.x);}
    inline bool operator <(const Line &b)const{return sgn(ang-b.ang)?sgn(ang-b.ang)<0:sgn(v*(b.p-p))<0;}
    friend node cross(const Line &a,const Line &b){return a.p+(a.v^(b.v*(b.p-a.p)/(b.v*a.v)));}
    inline bool Right(R node &b){return sgn(v*(b-p))<0;}
}L[N],q[N];
int n,m,tot,h,t;double area,res;
void HalfPlane(){
    sort(L+1,L+1+m);
    q[h=t=1]=L[1];
    fp(i,2,m)if(sgn(L[i].ang-L[i-1].ang)){
        while(h<t&&L[i].Right(p[t-1]))--t;
        while(h<t&&L[i].Right(p[h]))++h;
        q[++t]=L[i];
        if(h<t)p[t-1]=cross(q[t],q[t-1]);
    }
    while(h<t&&q[h].Right(p[t-1]))--t;
    if(t-h+1<=2)return;
    p[t]=cross(q[t],q[h]),p[t+1]=p[h];
    fp(i,h,t)res+=p[i]*p[i+1];
}
int main(){
//  freopen("testdata.in","r",stdin);
    n=read();
    fp(i,0,n-1)s[i].x=read(),s[i].y=read();
    s[n]=s[0];
    fp(i,1,n-1)area+=(s[i]-s[0])*(s[i+1]-s[0]);
    fp(i,0,n-1)L[++m]=Line(s[i],s[i+1]-s[i]);
    fp(i,1,n-1){
        double a=s[0].y-s[1].y+s[i+1].y-s[i].y;
        double b=s[1].x-s[0].x-s[i+1].x+s[i].x;
        double c=s[0].x*s[1].y-s[1].x*s[0].y+s[i+1].x*s[i].y-s[i].x*s[i+1].y;
        L[++m]=Line(sgn(b)?node(0,-c/b):node(-c/a,0),node(-b,a));
    }
    HalfPlane();
    printf("%.4lf\n",res/area);
    return 0;
}

转载于:https://www.cnblogs.com/bztMinamoto/p/10686266.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
SQLAlchemy 是一个 SQL 工具包和对象关系映射(ORM)库,用于 Python 编程语言。它提供了一个高级的 SQL 工具和对象关系映射工具,允许开发者以 Python 类和对象的形式操作数据库,而无需编写大量的 SQL 语句。SQLAlchemy 建立在 DBAPI 之上,支持多种数据库后端,如 SQLite, MySQL, PostgreSQL 等。 SQLAlchemy 的核心功能: 对象关系映射(ORM): SQLAlchemy 允许开发者使用 Python 类来表示数据库表,使用类的实例表示表中的行。 开发者可以定义类之间的关系(如一对多、多对多),SQLAlchemy 会自动处理这些关系在数据库中的映射。 通过 ORM,开发者可以像操作 Python 对象一样操作数据库,这大大简化了数据库操作的复杂性。 表达式语言: SQLAlchemy 提供了一个丰富的 SQL 表达式语言,允许开发者以 Python 表达式的方式编写复杂的 SQL 查询。 表达式语言提供了对 SQL 语句的灵活控制,同时保持了代码的可读性和可维护性。 数据库引擎和连接池: SQLAlchemy 支持多种数据库后端,并且为每种后端提供了对应的数据库引擎。 它还提供了连接池管理功能,以优化数据库连接的创建、使用和释放。 会话管理: SQLAlchemy 使用会话(Session)来管理对象的持久化状态。 会话提供了一个工作单元(unit of work)和身份映射(identity map)的概念,使得对象的状态管理和查询更加高效。 事件系统: SQLAlchemy 提供了一个事件系统,允许开发者在 ORM 的各个生命周期阶段插入自定义的钩子函数。 这使得开发者可以在对象加载、修改、删除等操作时执行额外的逻辑。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值