可能是因为太无聊了吧!可能是因为马上就要退役了吧!可能是因为……
反正我就是来写题解了,还能说什么好?数学确实很重要啊!
题目大概意思如下:
首先一张信用卡大体框架是矩形,但是在四个边缘进行了圆滑处理(四个角是半径为r的1/4圆,并且圆满足与矩形的边相切),如下图
现在告诉你信用卡的规格(高、宽、1/4圆半径)还有信用卡张数,并且告诉你每张信用卡在桌面上的坐标以及旋转角度(弧度制,我们默认最开始时信用卡正放于桌面),让你求包围所有信用卡的凸包周长。
反正我就是来写题解了,还能说什么好?数学确实很重要啊!
题目大概意思如下:
首先一张信用卡大体框架是矩形,但是在四个边缘进行了圆滑处理(四个角是半径为r的1/4圆,并且圆满足与矩形的边相切),如下图
现在告诉你信用卡的规格(高、宽、1/4圆半径)还有信用卡张数,并且告诉你每张信用卡在桌面上的坐标以及旋转角度(弧度制,我们默认最开始时信用卡正放于桌面),让你求包围所有信用卡的凸包周长。
输入的第一行是一个正整数 n,表示信用卡的张数。 第二行包含三个实数 a, b, r ,分别表示信用卡(圆滑处理前)竖直方向的长度、水平方向的长度,以及1/4圆的半径。 之后n行,每行包含三个实数 x ,y, θ,分别表示一张信用卡中心(即对角线交点)的横、纵坐标,以及绕中心逆时针旋转的弧度。
输出只有一行,包含一个实数,表示凸包的周长,四舍五入精确到小数点后2位。
这题不给样例不行:
我相信“凸包”这个词的出现已经有相当大的指导意义了,计算几何很明显,此题坑点不在凸包上,而在如何处理这些神奇的圆弧长度。
开始看着题果断神犇题,感觉好神奇,是不是原来的凸包算法都不能用了?不过很显然,不是的。
其实细心一点思考,应该把图形变一下(以样例3为例,作图略坑,要怪只能怪windows画图太垃圾>_<......)
很容易发现对顶的黑色夹角与蓝色夹角互补,证明略,而且凸包直线部分和内围直线部分凸包等长,实际上问题转化为求所有圆弧长度,这个只要知道内围凸包上每三个顶点对应的角度就好办了,内围凸包是模板算法,每一个信用卡对应四个点,然后各种三角函数乱搞就可以了,反正我表示三角函数烂成渣,还好比较happy一次AC。
输出只有一行,包含一个实数,表示凸包的周长,四舍五入精确到小数点后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 10010
using 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;
}