[SHTSC 2012] 信用卡凸包

来源:互联网 发布:西瓜影音有没有mac版 编辑:程序博客网 时间:2024/04/30 06:32
可能是因为太无聊了吧!可能是因为马上就要退役了吧!可能是因为……
反正我就是来写题解了,还能说什么好?数学确实很重要啊!

题目大概意思如下:
首先一张信用卡大体框架是矩形,但是在四个边缘进行了圆滑处理(四个角是半径为r的1/4圆,并且圆满足与矩形的边相切),如下图




现在告诉你信用卡的规格(高、宽、1/4圆半径)还有信用卡张数,并且告诉你每张信用卡在桌面上的坐标以及旋转角度(弧度制,我们默认最开始时信用卡正放于桌面),让你求包围所有信用卡的凸包周长。

输入的第一行是一个正整数 n,表示信用卡的张数。 第二行包含三个实数 a, b, r ,分别表示信用卡(圆滑处理前)竖直方向的长度、水平方向的长度,以及1/4圆的半径。 之后n行,每行包含三个实数 x ,y, θ,分别表示一张信用卡中心(即对角线交点)的横、纵坐标,以及绕中心逆时针旋转的弧度。 
 输出只有一行,包含一个实数,表示凸包的周长,四舍五入精确到小数点后2位。


这题不给样例不行:





我相信“凸包”这个词的出现已经有相当大的指导意义了,计算几何很明显,此题坑点不在凸包上,而在如何处理这些神奇的圆弧长度。
开始看着题果断神犇题,感觉好神奇,是不是原来的凸包算法都不能用了?不过很显然,不是的。
其实细心一点思考,应该把图形变一下(以样例3为例,作图略坑,要怪只能怪windows画图太垃圾>_<......)



很容易发现对顶的黑色夹角与蓝色夹角互补,证明略,而且凸包直线部分和内围直线部分凸包等长,实际上问题转化为求所有圆弧长度,这个只要知道内围凸包上每三个顶点对应的角度就好办了,内围凸包是模板算法,每一个信用卡对应四个点,然后各种三角函数乱搞就可以了,反正我表示三角函数烂成渣,还好比较happy一次AC。




#include <iostream>#include <cstdio>#include <algorithm>#include <cmath>#define SetPoint(_x,_y) (a[++tot].x=_x,a[tot].y=_y)#define MaxN 10010using namespace std;const double pi=acos(-1);double w,h,r;int st[MaxN];int n,tot,top;double sqr(double x){return x*x;}struct point{double x,y;}a[4*MaxN];#define po const point &inline double xmul(po a,po b,po c){return (b.x-a.x)*(c.y-a.y)-(b.y-a.y)*(c.x-a.x);}inline double dist(po a,po b){return sqrt(sqr(a.x-b.x)+sqr(a.y-b.y));}inline bool cmp(po p,po q){double d=xmul(a[1],p,q);return d==0.0 ? dist(a[1],p)<dist(a[1],q):d>0;}inline void init(){double x,y,R,angle,base,_x,_y;cin>>n>>h>>w>>r;h/=2,w/=2,h-=r,w-=r;base=asin(h/sqrt(sqr(w)+sqr(h)));R=sqrt(sqr(h)+sqr(w));for(int i=1;i<=n;i++){scanf("%lf%lf%lf",&x,&y,&angle);_x=R*cos(angle+base);_y=R*sin(angle+base);SetPoint(x+_x,y+_y);SetPoint(x-_x,y-_y);_x=R*cos(angle-base);_y=R*sin(angle-base);SetPoint(x+_x,y+_y);SetPoint(x-_x,y-_y);}}inline double GetRoundPartAngle(po a,po b,po c){double mx=a.x-b.x,my=a.y-b.y;double nx=c.x-b.x,ny=c.y-b.y;if(mx*ny-nx*my==0.0) return 0.0;double ans=acos((mx*nx+my*ny)/(dist(a,b)*dist(c,b)));return pi-ans;}inline void work(){int pos=1;for(int i=2;i<=tot;i++)if(a[pos].y>a[i].y)pos=i;else if(a[pos].y==a[i].y)if(a[pos].x>a[i].x)pos=i;swap(a[1],a[pos]);sort(a+2,a+tot+1,cmp);st[++top]=1;st[++top]=2;for(int i=3;i<=tot;st[++top]=i++)while(top>2&&xmul(a[st[top-1]],a[st[top]],a[i])<=0)top--;double ans=dist(a[1],a[st[top]]);for(int i=1;i<top;i++)ans+=dist(a[st[i]],a[st[i+1]]);ans+=r*GetRoundPartAngle(a[st[top]],a[1],a[2]);ans+=r*GetRoundPartAngle(a[st[top-1]],a[st[top]],a[1]);for(int i=2;i<top;i++)ans+=r*GetRoundPartAngle(a[st[i-1]],a[st[i]],a[st[i+1]]);printf("%.2lf\n",ans);}int main(){freopen("card.in","r",stdin);freopen("card.out","w",stdout);init();work();return 0;}


0 0
原创粉丝点击