• 【计算几何】求半平面交的面积


    【题意】
    在一个有限大(-10 0000<=x,y<=10 0000)的平面坐标系上有n个半平面(注意有限的),每个半平面给出一条有向线段(x1,y1)——>(x2,y2)。
    每个半平面的有效区域都是左侧。求这n个半平面的交的面积。
    【输入文件】
    第一行一个整数n(1 <= n <= 2 0000)
    下来n个半平面。每个半平面一行四个整数x1,y1,x2,y2。(-100000 <= x1,y1,x2,y2 <= 100000)
    【输出文件】
    一行,输出n个半平面的交的面积(保留一位小数),如果有效面积不存在则输出"0.0"。
    【样例1输入】
    3
    1 1 9 9
    5 10 4 10
    0 3 0 2
    【样例1输出】
    50.0

    【样例2输入】
    4
    0 0 10 0
    10 0 10 10
    10 10 0 10
    11 11 11 0
    【样例2输出】
    0.0

    代码有5个主要函数:
    1.mult()1.mult()——求叉积
    2.jd(segment  sg1,segment  sg2)2.jd(segment ~~sg1,segment~~ sg2)——求交点
    3.satisfy(node p,segment  sg)psg线3.satisfy(node~ p,segment~~ sg)——判断p是否在sg的左边或线上
    4.cmp(segment  sg1,segment  sg24.cmp(segment~~ sg1,segment ~~sg2)——按极角排序。(好处是最后得到的边在凸包上有序)
    5.solve()5.solve()求解函数

    其实有一个重点不能忽略,就是solve()里面先删队尾,再删对头。为什么呢?
    如果要删点的话
    如果要删有向线段的话,由图可知,两个在队列中的有向线段AB,CDoverrightarrow{AB},overrightarrow{CD}ABoverrightarrow{AB}的优先级更大。
    代码:

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    const int N=2e4+10;
    const double maxx=1e5;
    const double minn=-maxx;
    const double eps=1e-8;
    struct node
    {
    	double x,y;
    }p[N];int pl;
    struct segment 
    {
    	node p1,p2;
    	double angle;
    	segment(){}
    	void get_angle(){angle=atan2(p2.y-p1.y,p2.x-p1.x);}
    	segment(double x1,double y1,double x2,double y2){p1=(node){x1,y1};p2=(node){x2,y2};get_angle();}
    }seg[N],seglist[N];
    int head,tail,n;
    double mult(node p1,node p2,node p0)
    {
    	double x1,y1,x2,y2;
    	x1=p1.x-p0.x;
    	y1=p1.y-p0.y;
    	x2=p2.x-p0.x;
    	y2=p2.y-p0.y;
    	return x1*y2-x2*y1;
    }
    node jd(segment sg1,segment sg2)
    {
    	double t1=mult(sg1.p1,sg2.p2,sg2.p1);
    	double t2=mult(sg1.p2,sg2.p2,sg2.p1);
    	node p1=sg1.p1,p2=sg1.p2,p;
    	p.x=(t1*p2.x-t2*p1.x)/(t1-t2);
    	p.y=(t1*p2.y-t2*p1.y)/(t1-t2);
    	return p;
    }
    bool satisfy(node p,segment sg)
    {
    	return mult(p,sg.p2,sg.p1)<=eps;
    }
    bool cmp(segment sg1,segment sg2)
    {
    	if(sg1.angle<sg2.angle)return 1;
    	if(sg1.angle-sg2.angle<eps&&satisfy(sg1.p1,sg2)==1)return 1;
    	return 0;
    }
    void solve()
    {
    	sort(seg+1,seg+n+1,cmp);
    	int tp=1;for(int i=2;i<=n;i++)if(seg[i].angle-seg[tp].angle>eps)seg[++tp]=seg[i];
    	n=tp;
    	head=1;tail=0;
    	for(int i=1;i<=n;i++)
    	{
    		while(head<tail&&satisfy(jd(seglist[tail],seglist[tail-1]),seg[i])==0)--tail;
    		while(head<tail&&satisfy(jd(seglist[head],seglist[head+1]),seg[i])==0)++head;
    		seglist[++tail]=seg[i];
    	}
    	while(head<tail&&satisfy(jd(seglist[tail],seglist[tail-1]),seglist[head])==0)--tail;
    	while(head<tail&&satisfy(jd(seglist[head],seglist[head+1]),seglist[tail])==0)++head;
    	pl=0;
    	for(int i=head;i<tail;i++)p[++pl]=jd(seglist[i],seglist[i+1]);
    	p[++pl]=jd(seglist[head],seglist[tail]);
    	double ans=0;
    	for(int i=3;i<=pl;i++)ans+=mult(p[i],p[i-1],p[1]);
    	printf("%.1lf
    ",fabs(ans)/2.0);
    }
    int main()
    {
    	scanf("%d",&n);
    	seg[1]=segment(minn,minn,maxx,minn);
    	seg[2]=segment(maxx,minn,maxx,maxx);
    	seg[3]=segment(maxx,maxx,minn,maxx);
    	seg[4]=segment(minn,maxx,minn,minn);
    	n+=4;
    	for(int i=5;i<=n;i++)
    	{
    		double x1,y1,x2,y2;scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
    		seg[i]=segment(x1,y1,x2,y2);
    	}
    	solve();
    	return 0;
    }
    
  • 相关阅读:
    ASP.NET MVC3书店第十节 为网站导航与局部设计做最后的修改(转)
    利用IIS作为宿主 发布你的WCF Service(转)
    ASP.NET MVC3书店第九节 注册与下订单(第一部分)(转)
    ASP.NET MVC3书店第八节 使用Ajax的购物车(第二部分)(转)
    ASP.NET MVC3书店第七节 用户及身份验证(转)
    ASP.NET MVC3 快速入门第六节 增加一个追加数据的方法和一个追加数据的视图(转)
    ASP.NET MVC3书店第一节 概述(转)
    SQL Server Script 积累
    批处理命令行CMD启动停止重启IIS的命令(转)
    ASP.NET MVC3书店第五节 表单编辑(第三部分)(转)
  • 原文地址:https://www.cnblogs.com/zsyzlzy/p/12373918.html
Copyright © 2020-2023  润新知