这算是凸包模板的拓展吧,其实只要理解了和模板几乎一样呀…
做法:
其实只要把每个做了圆弧处理的长方形把四个四分之一圆去掉,再切成一个长方形,把那4个点加入点集,做一遍凸包,最后加上有个圆的周长就好了QAQ 是不是很简单
上代码
#include<iostream>
#include<iomanip>
#include<cstdio>
#include<cmath>
#include<string.h>
#include<algorithm>
#define For(i,f,l) int pd=(f<l)*1+(l<=f)*-1;for(i=f;i!=l+pd;i+=pd)
#define pi 3.1415926535//π还是自己写上方向呀
using namespace std;
struct point//定义一个点
{double x,y;};
double sqr(double a)//平方
{return a*a;}
int i,j,k,m,n,h,t;
point Point[100001],check[100001];
bool cmp(point a,point b)//根据坐标排序
{
if(a.y!=b.y)return a.y>b.y;
return a.x>b.x;
}
double far(point a,point b)
{return sqrt(sqr(a.x-b.x)+sqr(a.y-b.y));}//求两点之间的长度
double side(point a,point b,point c)//凸包做法的核心部分,详见凸包模板
{
return a.x*b.y+a.y*c.x+b.x*c.y-a.x*c.y-a.y*b.x-b.y*c.x;
}
void Around()//凸包做法的核心部分,详见凸包模板
{
h=n+1;
t=n+1;
int i;
check[t++]=Point[1];
for(i=1;i<=n;i++)
{
check[t]=Point[i];
if(side(check[n],Point[i],Point[i+1]))break;
}
if(n<2)return;
check[++t]=check[--h]=Point[++i];
if(side(check[n-1],check[n],check[n+1])<0)swap(check[n-1],check[n]);
for(++i;i<=n;i++)
{
if(side(check[h+1],check[h],Point[i])<0&&side(check[t-1],check[t],Point[i])>0)continue;
while(t-h>1&&side(check[h+1],check[h],Point[i])>=0)++h;
check[--h]=Point[i];
while(t-h>1&&side(check[t-1],check[t],Point[i])<=0)--t;
check[++t]=Point[i];
}
}
int main()
{
cin>>n;
double a,b,R,X,Y,th;
cin>>a>>b>>R;
a-=R*2;//切掉后的边长
b-=R*2;
double Long=sqrt(sqr(a)+sqr(b))/2;//算出对角线的一半
double An[4];//方便计算4个点的坐标
//这个公式就不一一说明了,自己总可以推出来QAQ
An[0]=atan(a/b);
An[1]=pi-An[0];
An[2]=pi+An[0];
An[3]=2*pi-An[0];
double ans=R*2*pi;//现在ans里放一个圆的周长
for(i=1;i<=n*4;i+=4)
{
cin>>X>>Y>>th;
for(j=0;j<4;j++)
{//把4个点加入点集
Point[i+j].x=cos(th+An[j])*Long+X;
Point[i+j].y=sin(th+An[j])*Long+Y;
}
}
n=n*4;//点的个数=n*4
//模板凸包做法
sort(Point+1,Point+n+1,cmp);
Around();
double fX=check[h].x,fY=check[h].y;
for(i=h;i<t;i++)
{
ans+=far(check[i],check[i+1]);//一条一条边加上
}
cout<<fixed<<setprecision(2)<<ans;//输出ans
return 0;
}
凸包的题都还算比较有难度,还是要思考后在动手QAQ