poj 2451 (半平面求交)

半平面求交,按着zzy论文里的方法对着写就可以了,这题数据还是比较厚道的

#include<stdio.h>
#include<math.h>
#include<algorithm>
using namespace std;
#define eps 1e-8
const int maxn=20005;
int dcmp(double k){
    return (k>eps)-(k<-eps);
}
struct point{
    double x,y;
    point(double xx=0,double yy=0){ x=xx;y=yy;}
    point rev(point r){ return point(2*x-r.x,2*y-r.y);}
    point operator-(point r){ return point(x-r.x,y-r.y);}
    point operator+(point r){ return point(x+r.x,y+r.y);}
    bool operator==(point r){ return !dcmp(x-r.x)&&!dcmp(y-r.y);}
    int operator*(point r){ return dcmp(r.x*y-x*r.y);}
    void print(){ printf("(%lf,%lf)\n",x,y);}
}p_down[maxn],p_up[maxn],list[maxn];
struct line{
    point u,v;
    line(point uu=point(0,0),point vv=point(0,0)){ u=uu;v=vv;}
    void init(){ scanf("%lf%lf%lf%lf",&u.x,&u.y,&v.x,&v.y);}
    int operator*(line r){ return (v-u)*(r.v-r.u);}
    bool str(){ return !dcmp(u.x-v.x)&&dcmp(v.y-u.y)<0;}
    void print(){ printf("(%lf,%lf),(%lf,%lf)\n",u.x,u.y,v.x,v.y);}
}q[maxn],l_down[maxn],l_up[maxn],pivot,l1,l2,l3,l4;
point intersection(point u1,point u2,point v1,point v2){//直线交点
	point ret=u1;
	double t=((u1.x-v1.x)*(v1.y-v2.y)-(u1.y-v1.y)*(v1.x-v2.x))
			/((u1.x-u2.x)*(v1.y-v2.y)-(u1.y-u2.y)*(v1.x-v2.x));
	ret.x+=(u2.x-u1.x)*t;
	ret.y+=(u2.y-u1.y)*t;
	return ret;
}
double area_polygon(point* p,int k){//多边形面积
	double s1=0,s2=0;
	for(int i=0;i<k;i++)
		s1+=p[(i+1)%k].y*p[i].x,s2+=p[(i+1)%k].y*p[(i+2)%k].x;
	return fabs(s1-s2)/2;
}
int cmp(line a,line b){
    return a*b<0||a.str()&&!b.str();
}
bool is_left(line a,line b){
    return a*line(a.u,b.v)>0;
}
int n;
int cnt_down,cnt_up;
int top_down,top_up;
void init(){
    l1=line(point(-1,0),point(10001,0));
    l2=line(point(10001,10000),point(-1,10000));
    l3=line(point(10000,-1),point(10000,10001));
    l4=line(point(0,10001),point(0,-1));
    q[0]=l1;q[1]=l2;q[2]=l3;q[3]=l4;
    n+=4;
    for(int i=4;i<n;i++) q[i].init();
    cnt_down=cnt_up=0;
    for(int i=0;i<n;i++){
        if(q[i]*pivot>=0) l_down[cnt_down++]=q[i];
        else l_up[cnt_up++]=q[i];
    }
    sort(l_down,l_down+cnt_down,cmp);
    sort(l_up,l_up+cnt_up,cmp);
    int ct1,ct2;
    ct1=1;
    for(int i=1;i<cnt_down;i++){
        if(l_down[i]*l_down[ct1-1]>0) l_down[ct1++]=l_down[i];
        else if(is_left(l_down[i],l_down[ct1-1])) l_down[ct1-1]=l_down[i];
    }
    cnt_down=ct1;
    ct2=1;
    for(int i=1;i<cnt_up;i++){
        if(l_up[i]*l_up[ct2-1]>0) l_up[ct2++]=l_up[i];
        else if(is_left(l_up[i],l_up[ct2-1])) l_up[ct2-1]=l_up[i];
    }
    cnt_up=ct2;
    top_down=0;
    p_down[0]=l_down[0].u;
    point rear,now;
    rear=l_down[0].v;
    for(int i=1;i<cnt_down;i++){
        point now=intersection(p_down[top_down],rear,l_down[i].u,l_down[i].v);
        while(top_down&&now.x<=p_down[top_down].x){
            top_down--;
            now=intersection(p_down[top_down],p_down[top_down+1],l_down[i].u,l_down[i].v);
        }
        p_down[++top_down]=now;
        rear=l_down[i].v==now?l_down[i].u:l_down[i].v;
    }
    p_down[++top_down]=rear;
    int t1=(p_down[1]-p_down[0])*point(0,-1);
    int t2=(p_down[top_down]-p_down[top_down-1])*point(0,-1);
    if(t1<0||t1==0&&p_down[1].y>p_down[0].y) p_down[0]=p_down[1].rev(p_down[0]);
    if(t2<0||t2==0&&p_down[top_down].y<p_down[top_down-1].y) p_down[top_down]=p_down[top_down-1].rev(p_down[top_down]);
    top_up=0;
    p_up[0]=l_up[0].u;
    rear=l_up[0].v;
    for(int i=1;i<cnt_up;i++){
        point now=intersection(p_up[top_up],rear,l_up[i].u,l_up[i].v);
        while(top_up&&now.x>=p_up[top_up].x){
            top_up--;
            now=intersection(p_up[top_up],p_up[top_up+1],l_up[i].u,l_up[i].v);
        }
        p_up[++top_up]=now;
        rear=l_up[i].v==now?l_up[i].u:l_up[i].v;
    }
    p_up[++top_up]=rear;
    if((p_up[1]-p_up[0])*point(0,-1)>=0) p_up[0]=p_up[1].rev(p_up[0]);
    if((p_up[top_up]-p_up[top_up-1])*point(0,-1)>=0) p_up[top_up]=p_up[top_up-1].rev(p_up[top_up]);
}
point ll,rr;
int ct1,ct2,p1,p2,p3,p4;
double area(){
    ct1=1;ct2=top_up-1;
    bool find=false;
    while(ct1<=top_down&&ct2>=0){
        if((p_up[ct2]-p_up[ct2+1])*(p_down[ct1]-p_up[ct2+1])<=0) ct1++;
        else if((p_down[ct1]-p_down[ct1-1])*(p_up[ct2]-p_down[ct1-1])>=0) ct2--;
        else{
            ll=intersection(p_down[ct1-1],p_down[ct1],p_up[ct2],p_up[ct2+1]);
            p1=ct2;p2=ct1;
            find=true;
            break;
        }
    }
    if(!find){
        //puts("fail!");
        return 0;
    }
    ct1=top_down-1;ct2=1;
    while(ct2<=top_up&ct1>=0){
        if((p_down[ct1]-p_down[ct1+1])*(p_up[ct2]-p_down[ct1+1])<=0) ct2++;
        else if((p_up[ct2]-p_up[ct2-1])*(p_down[ct1]-p_up[ct2-1])>=0) ct1--;
        else{
            rr=intersection(p_up[ct2-1],p_up[ct2],p_down[ct1],p_down[ct1+1]);
            p3=ct2;p4=ct1;
            break;
        }
    }
    int ct=0;
    list[ct++]=ll;
    for(int i=p1;i>=p3;i--) list[ct++]=p_up[i];
    list[ct++]=rr;
    for(int i=p4;i>=p2;i--) list[ct++]=p_down[i];

    return area_polygon(list,ct);
}
int main(){
    pivot.u=point(0,0);pivot.v=point(0,-1);
    while(scanf("%d",&n)!=EOF){
        init();
        printf("%.1lf\n",area()+eps);
    }
    return 0;
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值