HDU 4667 Building Fence(求凸包的周长)
2016-05-19 19:15
531 查看
A-BuildingFence
TimeLimit:1000MSMemoryLimit:65535KB64bitIOFormat:%I64d&%I64u
SubmitStatus
Description
Longlongago,thereisafamousfarmernamedJohn.Heownsabigfarmandmanycows.Therearetwokindsofcowsonhisfarm,oneisFriesian,andanotheroneisAyrshire.Eachcowhasitsownterritory.Indetail,theterritoryofFriesianisacircle,andofAyrshireisatriangle.Itisobviousthateachcowdoesn'twanttheirterritoryviolatedbyothers,sotheterritorieswon'tintersect.
Sincethewinterisfalling,FJhastobuildafencetoprotectallhiscowsfromhungrywolves,makingtheterritoryofcowsinthefence.Duetothefinancialcrisis,FJiscurrentlylackofmoney,hewantsthetotallengthofthefenceminimized.Sohecomestoyou,thegreatestprogrammereverforhelp.Pleasenotethatthepartoffencedon'thavetobeastraightline,itcanbeacurveifnecessary.
Input
Theinputcontainsseveraltestcases,terminatedbyEOF.Thenumberoftestcasesdoesnotexceed20.
EachtestcasebeginswithtwointegersNandM(0≤N,M≤50,N+M>0)whichdenotesthenumberoftheFriesianandAyrshirerespectively.ThenfollowsN+Mlines,eachlinerepresentingtheterritoryofthecow.EachofthefirstNlinescontainsthreeintegersXi,Yi,Ri(1≤Ri≤500),denotesthecoordinatesofthecircle'scentreandradius.TheneachoftheremainingMlinescontainssixintegersX1i,Y1i,X2i,Y2i,X3i,Y3i,denotesthecoordinatesofthetrianglevertices.Theabsolutevalueofthecoordinateswon'texceed10000.
Output
Foreachtestcase,printasinglelinecontainingtheminimalfencelength.Youroutputshouldhaveanabsoluteerrorofatmost1e-3.
SampleInput
11
441
000220
SampleOutput
15.66692
Hint
TimeLimit:1000MSMemoryLimit:65535KB64bitIOFormat:%I64d&%I64u
Submit
Description
Longlongago,thereisafamousfarmernamedJohn.Heownsabigfarmandmanycows.Therearetwokindsofcowsonhisfarm,oneisFriesian,andanotheroneisAyrshire.Eachcowhasitsownterritory.Indetail,theterritoryofFriesianisacircle,andofAyrshireisatriangle.Itisobviousthateachcowdoesn'twanttheirterritoryviolatedbyothers,sotheterritorieswon'tintersect.
Sincethewinterisfalling,FJhastobuildafencetoprotectallhiscowsfromhungrywolves,makingtheterritoryofcowsinthefence.Duetothefinancialcrisis,FJiscurrentlylackofmoney,hewantsthetotallengthofthefenceminimized.Sohecomestoyou,thegreatestprogrammereverforhelp.Pleasenotethatthepartoffencedon'thavetobeastraightline,itcanbeacurveifnecessary.
Input
Theinputcontainsseveraltestcases,terminatedbyEOF.Thenumberoftestcasesdoesnotexceed20.
EachtestcasebeginswithtwointegersNandM(0≤N,M≤50,N+M>0)whichdenotesthenumberoftheFriesianandAyrshirerespectively.ThenfollowsN+Mlines,eachlinerepresentingtheterritoryofthecow.EachofthefirstNlinescontainsthreeintegersXi,Yi,Ri(1≤Ri≤500),denotesthecoordinatesofthecircle'scentreandradius.TheneachoftheremainingMlinescontainssixintegersX1i,Y1i,X2i,Y2i,X3i,Y3i,denotesthecoordinatesofthetrianglevertices.Theabsolutevalueofthecoordinateswon'texceed10000.
Output
Foreachtestcase,printasinglelinecontainingtheminimalfencelength.Youroutputshouldhaveanabsoluteerrorofatmost1e-3.
SampleInput
11
441
000220
SampleOutput
15.66692
Hint
Pleaseseethesamplepictureformoredetails,thefenceishighlightedwithred.
题意:给定n个圆,m个三角形,求凸包的周长,详见上图。 题解:这个题有一种很水的做法就是把圆分成1000个点,然后直接对这些点求凸包。 不推荐这个方法,属于水过的,换个精度高的数据没准就WA了,正确做法如下: 把三角形的所有点视为单个点,标记三角形每个点的id为-1,-2,-3,-4.......放到一个集合P中, 求这些点与圆的切线的交点,把这些点再放到集合P中,标记他们的id为圆的数组下标。 再求圆与圆之间的内切线外切线与圆的交点,再放到集合P中,标记他们的id为圆的数组下标, 把这些点进行凸包就可以求出周长了,id相同的点要算弧长。很多很多细节问题需要注意,已写到注释里。 另外注意在没有三角形只有一个圆的情况下要单独考虑,因为不会通过点和圆之间 的切线以及圆和圆之间的切线产生点,所以要单独判断然后输出圆的面积, continue即可。 对于数组为什么开2W,目前未知,求大神解答。
#include<iostream> #include<math.h> #include<stdio.h> #include<string.h> #include<algorithm> #include<stdlib.h> #include<vector> constdoublePI=acos(-1.0); usingnamespacestd; structPoint{ doublex,y; intid; Point(doublex=0,doubley=0,intid=-1):x(x),y(y){}//构造函数,方便代码编写 }; typedefPointVector;//从程序上实现,Vector只是Point的别名 structCircle{ Pointc; doubler; Circle(){} Circle(Pointc,doubler):c(c),r(r){} Pointpoint(doublea){ returnPoint(c.x+cos(a)*r,c.y+sin(a)*r); } }; //定义 #defineN50000//数组最小开20000为什么开20000没算对 //我算的是150+300+C(50,2)*4即三角形的点+这些点与圆的切点+圆之间的切点不到6000 //开大点就完了开500000才42344KB上限65536够用了 Pointp ; Pointch ; Circlec ; Pointa[10],b[10]; Pointq ; intm,n,t; //点-点=向量 Vectoroperator-(PointA,PointB) { returnVector(A.x-B.x,A.y-B.y); } //运算符重载 booloperator<(constPoint&a,constPoint&b) { returna.x<b.x||(a.x==b.x&&a.y<b.y); } constdoubleeps=1e-10; //三态函数精度问题 intdcmp(doublex) { if(fabs(x)<eps)return0;elsereturnx<0?-1:1; } booloperator==(constPoint&a,constPoint&b) { returndcmp(a.x-b.x)==0&&dcmp(a.y-b.y)==0; } doubleDot(VectorA,VectorB) { returnA.x*B.x+A.y*B.y; } //求向量的值 doubleLength(VectorA) { returnsqrt(Dot(A,A)); } //求夹角 doubleAngle(VectorA,VectorB) { returnacos(Dot(A,B)/Length(A)/Length(B));//a*b=|a|*|b|*cos(c) } //叉积 doubleCross(VectorA,VectorB) { returnA.x*B.y-A.y*B.x; } //求凸包模板 intConvexHull(Point*p,intn,Point*ch)//注意是*ch { sort(p,p+n);//这个要用到<重载运算符 n=unique(p,p+n)-p;//这个要用到==重载运算符 intm=0; for(inti=0;i<n;i++) { //注意:可以共线时"<"改为"<=" while(m>1&&Cross(ch[m-1]-ch[m-2],p[i]-ch[m-2])<=0)m--; ch[m++]=p[i]; } intk=m; for(inti=n-2;i>=0;i--)//注意是--不是++ { while(m>k&&Cross(ch[m-1]-ch[m-2],p[i]-ch[m-2])<=0)m--; ch[m++]=p[i]; } if(n>1)m--; returnm;//别忘了加m } Pointreadpoint() { doublex,y; scanf("%lf%lf",&x,&y); returnPoint(x,y); } voidreadcircle(Circle&c) { scanf("%lf%lf%lf",&c.c.x,&c.c.y,&c.r); } //点到圆的切线v存的是切点 intpcl(Pointp,Circleo,Vector*v)//点到圆的切线的切点,考虑不同情况 { Vectoru=p-o.c; doubled=Length(u); doublea=atan2(u.y,u.x);//指向量u与x正半轴的夹角起点是圆心指向p点 if(d<o.r)return0;//圆内 elseif(dcmp(d-o.r)==0)//圆上 { v[0]=o.point(a); return1; } else//圆外两个外切点 { doubleang=acos(o.r/d); v[0]=o.point(a+ang); v[1]=o.point(a-ang); return2; } } //两圆相离的时候的外公共切线 intccl(Circlec1,Circlec2,Point*a,Point*b) { intcnt=0; if(dcmp(c1.r-c2.r)<0)//保证结果为正值 { swap(c1,c2); swap(a,b); } Vectoru=c2.c-c1.c; doubled=Length(u); doubleang=atan2(u.y,u.x); //有外公切线 doubleg=acos((c1.r-c2.r)/d); a[cnt]=c1.point(ang+g); b[cnt]=c2.point(ang+g); cnt++; a[cnt]=c1.point(ang-g); b[cnt]=c2.point(ang-g); cnt++; returncnt; } doublearc(Pointa,Pointb,Circlec)//a,b逆时针穿过圆c外面的的圆弧长 { Pointu=a-c.c,v=b-c.c; doubleang=Angle(u,v);//Angle是夹角模板中的angle=atan2(v.y,v.x)是极角 if(Cross(u,v)>eps) returnang*c.r; return(PI*2.0-ang)*c.r; } intmain() { while(scanf("%d%d",&n,&m)==2) { m=m*3; for(inti=0;i<n;i++)//圆 readcircle(c[i]); for(inti=0;i<m;i++)//三角形 { p[i]=readpoint(); p[i].id=-i*3-1;//三角形的id标记成负数 } if(n==1&&!m) { printf("%.5f\n",PI*2*c[0].r);;//输出一个圆的面积 continue; } //注意swap是把数值换位置n和m不换位置 for(inti=m-1;i>=0;i--)//三角形的点已经乘过3了 for(intj=0;j<n;j++)//圆 { Pointv[2];//存放切点 intnum=pcl(p[i],c[j],v);//点到圆的切线p是点c是圆v是切点num是切点个数 for(intk=0;k<num;k++) { //从三角形的点中继续添加点 p[m]=v[k];//把切点放入点集中 p[m].id=j;//给新的点做标记这个点是第j个圆的 m++; } } for(intj=0;j<n;j++) for(inti=j+1;i<n;i++) { intnum=ccl(c[j],c[i],a,b);//圆和圆之间的外切点 for(intk=0;k<num;k++) { p[m]=a[k]; p[m].id=j; m++; p[m]=b[k]; p[m].id=i; m++; } } m=ConvexHull(p,m,ch); memcpy(p,ch,sizeof(ch)); doublelen=0.0; p[m]=p[0]; for(inti=0;i<m;i++) { if(p[i].id==p[i+1].id)//如果标记相等说明在一个圆上 { len+=arc(p[i],p[i+1],c[p[i].id]);//两个点绕圆弧逆时针的长 } else { len+=Length(p[i]-p[i+1]);//不在一个圆上输出算直线距离 } } printf("%.5f\n",len); } return0; }
相关文章推荐
- 键盘样式(UIKeyboardType)
- Java问题总结33之利用UUID生成全局唯一码(Scala环境运行)
- 【Arduino官方教程第一辑】示例程序 4-9 串口双向调用(使用ASCII字符串)
- 加载图片显示时的图片变形问题(UIImageView)
- 你该知道的 TValue
- Uva1605——Building for UN
- Longest Increasing Subsequence
- OData入门:OData Java和SAP UI5的几个帖子
- 理解JPA注解@GeneratedValue
- Jsp注册界面——request对象
- ServletFileUpload.parseRequest()为空
- android:fillViewport="true"
- 创建型模式之Builder模式及实现
- java 生成22位UUID 改造
- autoinstall ISO build
- NanUI for Winform 使用示例【第一集】——山寨个代码编辑器
- Ui
- (转载)NGUI研究院之为什么Scene视图中不显示Polygon Collider2D(十七)
- SDUT 2169 Sequence dp减枝区间划分
- IOS UIButton使用详解