LightOJ 1130 Intersection between Circle and Rectangle
来源:互联网 发布:ds cloud windows 编辑:程序博客网 时间:2024/05/01 10:09
题目链接 http://lightoj.com/volume_showproblem.php?problem=1130
题意:求所给出的圆与矩形的重叠部分的面积
思路:构造出所求图形,求出矩形与圆的交点,将阴影部分分成若干三角形和扇形,分块计算面积。题目对计算精度要求很高
这个题因为精度问题纠结了好久……最后参考了一下别人的思路。
参考博文 http://blog.csdn.net/pvpishard/article/details/7220876
关于参考博文中提到的奇葩问题,我测试的时候全是WA……应该是LightOJ的测试数据更新了吧。
关于参考博文中提到“最精简的求1/sqrt()”的函数貌似精度只有小数点后3位,应该是不满足本题要求(小数点后6位)。
这个函数我也试着了解了一下,在较低精度要求下真的快不少!
参考链接 http://game.chinaitlab.com/devdoc/723647.html
http://www.cnblogs.com/nihgwu/archive/2006/08/04/467597.html
这个题应该还有更好的思路,LightOJ上目前最小MEMORY占用居然只有228……欢迎留言,一起讨论
#include <stdio.h>#include <math.h>const double PI=acos(-1.0);const double STD=1e-9; //浮点数大小判断标准struct Point{double x,y;void disp (){printf("x=%lf y=%lf\n",x,y);}Point friend Vec (Point a,Point b) //构造向量{Point res;res.x=a.x-b.x;res.y=a.y-b.y;return res;}}pt[20];struct Line{Point s,e;void set (double sx,double sy,double ex,double ey){s.x=sx;s.y=sy;e.x=ex;e.y=ey;}}line[4];struct Circle{Point c;double r;}cir;int point_num; //记录需要计算的点的数量bool out[20]; //标记点与圆的位置关系,在圆内和圆上为false,在圆外为truevoid Find (Line l,int mode) //寻找矩形与圆的交点,结果保存在pt数组中{Point temp;double t,d;switch (mode){case 0: //寻找"左至右"边与圆的交点if (fabs(cir.c.y-l.s.y) > cir.r) //与圆不相交return;d=cir.c.y-l.s.y;t=sqrt(fabs(cir.r*cir.r-d*d));temp.y=l.s.y;temp.x=cir.c.x-t;if (temp.x>l.s.x && temp.x<l.e.x)pt[point_num++]=temp;temp.x=cir.c.x+t;if (temp.x>l.s.x && temp.x<l.e.x)pt[point_num++]=temp;break;case 1: //寻找"上至下"边与圆的交点if (fabs(cir.c.x-l.s.x) > cir.r) //与圆不相交return;d=cir.c.x-l.s.x;t=sqrt(fabs(cir.r*cir.r-d*d));temp.x=l.s.x;temp.y=cir.c.y+t;if (temp.y<l.s.y && temp.y>l.e.y)pt[point_num++]=temp;temp.y=cir.c.y-t;if (temp.y<l.s.y && temp.y>l.e.y)pt[point_num++]=temp;break;case 2: //寻找"右至左"边与圆的交点if (fabs(cir.c.y-l.s.y) > cir.r) //与圆不相交return;d=cir.c.y-l.s.y;t=sqrt(fabs(cir.r*cir.r-d*d));temp.y=l.s.y;temp.x=cir.c.x+t;if (temp.x<l.s.x && temp.x>l.e.x)pt[point_num++]=temp;temp.x=cir.c.x-t;if (temp.x<l.s.x&&temp.x>l.e.x)pt[point_num++]=temp;break;case 3: //寻找"下至上"边与圆的交点if (fabs(cir.c.x-l.s.x) > cir.r) //与圆不相交return;d=cir.c.x-l.s.x;t=sqrt(fabs(cir.r*cir.r-d*d));temp.x=l.s.x;if (l.s.y<l.e.y) //寻找"下至上"边与圆的交点temp.y=cir.c.y-t;if (temp.y>l.s.y && temp.y<l.e.y)pt[point_num++]=temp;temp.y=cir.c.y+t;if (temp.y>l.s.y && temp.y<l.e.y)pt[point_num++]=temp;}}/* void Find (Line l) //网上别人代码的修改+注释版{Point temp;double t,d;if (fabs(l.s.x-l.e.x) < STD) //起始横坐标相同,即竖直线{if (fabs(cir.c.x-l.s.x) > cir.r) //起点在圆外return;d=cir.c.x-l.s.x;t=sqrt(fabs(cir.r*cir.r-d*d));temp.x=l.s.x;if (l.s.y<l.e.y) //寻找"下至上"边与圆的交点{temp.y=cir.c.y-t;if (temp.y>l.s.y && temp.y<l.e.y)pt[point_num++]=temp;temp.y=cir.c.y+t;if (temp.y>l.s.y && temp.y<l.e.y)pt[point_num++]=temp;}else //寻找"上至下"边与圆的交点{temp.y=cir.c.y+t;if (temp.y<l.s.y && temp.y>l.e.y)pt[point_num++]=temp;temp.y=cir.c.y-t;if (temp.y<l.s.y && temp.y>l.e.y)pt[point_num++]=temp;}}else //起始横坐标不同,即水平线{if (fabs(cir.c.y-l.s.y) > cir.r) //起点在圆外return;d=cir.c.y-l.s.y;t=sqrt(fabs(cir.r*cir.r-d*d));temp.y=l.s.y;if (l.s.x<l.e.x) //寻找"左至右"边与圆的交点{temp.x=cir.c.x-t;if (temp.x>l.s.x && temp.x<l.e.x)pt[point_num++]=temp;temp.x=cir.c.x+t;if (temp.x>l.s.x && temp.x<l.e.x)pt[point_num++]=temp;}else //寻找"右至左"边与圆的交点{temp.x=cir.c.x+t;if (temp.x<l.s.x && temp.x>l.e.x)pt[point_num++]=temp;temp.x=cir.c.x-t;if (temp.x<l.s.x&&temp.x>l.e.x)pt[point_num++]=temp;}}}*/void Input () //输入及构造部分{scanf("%lf%lf%lf",&cir.c.x,&cir.c.y,&cir.r);double lx,ly,rx,ry;scanf("%lf%lf%lf%lf",&lx,&ly,&rx,&ry);line[0].set(lx,ry,rx,ry); //上边-左至右line[1].set(rx,ry,rx,ly); //右边-上至下line[2].set(rx,ly,lx,ly); //下边-右至左line[3].set(lx,ly,lx,ry); //左边-下至上//求出需要考虑的点,即矩形顶点以及矩形与圆的交点point_num=0;pt[point_num++]=line[0].s;Find (line[0],0);pt[point_num++]=line[1].s;Find (line[1],1);pt[point_num++]=line[2].s;Find (line[2],2);pt[point_num++]=line[3].s;Find (line[3],3);//for (int i=0;i<point_num;i++) printf("Point %d ",i),pt[i].disp();}double get_dis (Point a,Point b) //计算两点间距离{return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));}double get_dis2 (Point a,Point b) //计算两点间距离的平方{return (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y);}void Judge (){double t;for (int i=0;i<point_num;i++){t=get_dis(pt[i],cir.c);if (t>cir.r+STD)out[i]=true;else out[i]=false;}}double get_cj (Point a,Point b) //计算叉积{return a.x*b.y-a.y*b.x;}double get_dj(Point a,Point b) //计算点积{return a.x*b.x+a.y*b.y;}double get_tri (Point a,Point b) //计算三角形面积{return get_cj (Vec(a,cir.c),Vec(b,cir.c))/2;}double get_sec (Point a,Point b) //计算扇形面积{double da=get_dis2 (a,cir.c);double db=get_dis2 (b,cir.c);double cj=get_cj (Vec(a,cir.c),Vec(b,cir.c));double dj=get_dj (Vec(a,cir.c),Vec(b,cir.c));double dsin=cj/sqrt(da*db); //da,db是平方过的,如果先开方再乘会损失精度WA……double alpha=asin(dsin);//asin函数求出的角是0到90度的,需要根据实际情况还原到原来的大小if (dj < -STD) //当夹角大于90度时if (alpha>0)alpha=PI-alpha;elsealpha=-PI-alpha;return alpha*cir.r*cir.r/2;}double Deal (){if (cir.r < STD)return 0;Judge ();double ans=0;for (int i=0;i<point_num;i++){if (out[i] == false && out[(i+1)%point_num] == false)//如果两个点都不在圆外ans+=get_tri(pt[i],pt[(i+1)%point_num]);else //若至少有一点在圆外ans+=get_sec(pt[i],pt[(i+1)%point_num]);}return fabs(ans); //用叉积可能负面积}int main (){int T;scanf("%d",&T);for (int cas=1;cas<=T;cas++){Input ();printf("Case %d: %.8lf\n",cas,Deal());}return 0;}/*24 4 41 1 3 34 4 41 1 7 7OutCase 1: 3.93987658Case 2: 35.75950633*/
- LightOJ 1130 Intersection between Circle and Rectangle
- 有史以来最奇葩的事情发生了!!lightOJ 1130 Intersection between Circle and Rectangle
- HDU-Rectangle and Circle
- intersection of circle and sector
- HDU1221---Rectangle and Circle HDU(94)
- 【数学】hdu 1221 Rectangle and Circle
- 计算几何-hdoj-1221-Rectangle and Circle
- hdoj 1221 Rectangle and Circle(判点的位置)
- hdu-1221--Rectangle and Circle(计算几何)
- opencv2 circle rectangle
- Circle in Square LightOJ
- hdu 1221 Rectangle and Circle(矩形与圆焦点问题)
- HDU 1221 Rectangle and Circle(判断圆与矩形是否相交)
- HDU 1221 Rectangle and Circle(判定圆与矩形是否相交)
- HDU 1221 Rectangle and Circle(判定圆与矩形是否相交)
- shape派生circle,rectangle,square
- LightOJ 1022 Circle in Square
- LightOj-1022-Circle in Square
- 用RSA加密Flash与ASP.Net之间的通信
- 设计模式四(装饰模式,采用python 实现)
- fgets,优先级问题导致Segmentation fault
- 低分辨率强制开启Win8分屏(Win8 Snap)功能方法
- oracle 自增序列
- LightOJ 1130 Intersection between Circle and Rectangle
- phpcms v9模板制作常用代码集合
- 双链表基本操作。
- 设计模式之桥接模式 及 c++ 实现
- 使panel中的行紧密排列
- dataGridView 显示行号
- the mystery of erasure
- MSSQL 2005 数据库变成可疑
- 数据库主体拥有数据库角色,无法删除