这道题BZOJ有权限,用学校的号A的,所以没有传送门,直接上题目描述~
(我才不会说在vijos上有也有这道题,因为我没测试过,nanana)
题目描述
输入样例
2
6.0 2.0 0.0
0.0 0.0 0.0
2.0 -2.0 1.5707963268
输出样例
21.66
提示
本样例中的2张信用卡的轮廓在上图中用实线标出,如果视1.5707963268为Pi/2(pi为圆周率),则其凸包的周长为16+4*sqrt(2)
限制
时间:10s 空间 128MB
解题分析
这道题很裸的凸包,但是有不少细节需要处理:
1.信用卡的长和宽是个问题
因为题目说的圆滑处理就是把四角磨圆,而不是额外增一圈,所以给出的信用卡的长和宽其实是有多出来的,需要砍去两个半径的长度。
2.旋转
还记得怎么旋转吗,其实我也不知道,^_^
3.一个圆
同经典题Wall一样,这道题也只需在凸包周长上再加一个圆的周长就行了。
4.精度问题
由于旋转涉及到三角函数,三角函数的大问题又是精度问题,所以建议用dcmp判断,不然快排,可能会让你开始怀疑 人生 C++
代码
#include<cmath>
#include<cstdio>
#include<algorithm>
using namespace std;
int n,m,tot;
double a,b,R,ans,eps=1e-10;
int dcmp(double x)
{
if (fabs(x)<eps) return 0;
return (x<0)?-1:1;
}
struct data{
double x,y;
data (double x=0.0,double y=0.0):x(x),y(y){}
bool operator < (const data b) const{
return dcmp(x-b.x)<0||(dcmp(x-b.x)==0&&dcmp(y-b.y)<0);
}
bool operator == (const data b) const{
return dcmp(x-b.x)==0&&dcmp(y-b.y)==0;
}
}p[400005],ch[400005],s[4],c[400005];
data operator + (const data a,const data b) {return data(a.x+b.x,a.y+b.y);}
data operator - (const data a,const data b) {return data(a.x-b.x,a.y-b.y);}
double dot (const data a,const data b) {return a.x*b.x+a.y*b.y;}
double cross(const data a,const data b) {return a.x*b.y-a.y*b.x;}
double leng(const data a) {return sqrt(dot(a,a));}
data _Rotate(const data a,const double rad) {return data(a.x*cos(rad)-a.y*sin(rad),a.x*sin(rad)+a.y*cos(rad));}
//旋转向量
inline void readd(double &x) //读入优化
{
x=0.0; int f=1; double t=1.0; char ch=getchar();
while ('0'>ch||ch>'9'){if (ch=='-') f=-f; ch=getchar();}
while ('0'<=ch&&ch<='9') {x=x*10+ch-'0'; ch=getchar();}
if (ch=='.'){
ch=getchar();
while ('0'<=ch&&ch<='9') {t/=10.0; x+=(ch-'0')*t; ch=getchar();}
}
x*=f;
}
void _init()
{
scanf("%d",&n); m=0;
readd(b); readd(a); readd(R);
a-=2*R; b-=2*R;
s[0]=data(a/2,b/2); s[1]=data(a/2,-b/2); s[2]=data(-a/2,b/2); s[3]=data(-a/2,-b/2); //方便编写
for (int i=1;i<=n;i++)
{
double x,y,z; readd(x); readd(y); readd(z);
for (int j=0;j<4;j++) c[++m]=data(x,y)+_Rotate(s[j],z);
}
}
void _work() //排序,由于本人强迫症,还去了个重。
{
sort(c+1,c+m+1);
int i=1,j; n=0;
while (i<=m)
{
j=i+1; ch[++n]=c[i];
while (j<=m&&c[i]==c[j]) j++;
i=j;
}
}
void _solve()
{
_work(); tot=0;
for (int i=1;i<=n;i++)
{
while (tot>1&&dcmp(cross(p[tot]-p[tot-1],ch[i]-p[tot-1]))<=0) tot--;
p[++tot]=ch[i];
}
int k=tot;
for (int i=n-1;i>0;i--)
{
while (tot>k&&dcmp(cross(p[tot]-p[tot-1],ch[i]-p[tot-1]))<=0) tot--;
p[++tot]=ch[i];
}
ans=R*2*3.1415926;
for (int i=1;i<tot;i++) ans+=leng(p[i+1]-p[i]);
printf("%0.2lf",ans);
}
int main()
{
_init();
_solve();
return 0;
}
PS:本博客过于简陋,再加上作者fhj水平过菜,如果各位神犇有建议,请多多指出,谢谢!