题意:
有nnn张信用卡,原本每张信用卡都是水平间距为bbb,垂直间距为aaa的矩形,现在要将四个角打磨成直角,使角变为14\frac{1}{4}41圆弧,并且每张卡的圆弧的半径都是rrr。给出平面上nnn张信用卡的中心点的位置和绕中心点逆时针旋转的弧度,求这nnn张信用卡的凸包。
方法:
因为有圆,圆的凸包是很难求的,所以先考虑点的凸包,在这里,比较特殊的点就是圆心,那么圆心的凸包是否和要求的凸包有一定联系?实际上要求的凸包长就是圆心的凸包长加以rrr为半径的圆的周长,下面给出一个证明。
(1)证明:任意凸nnn边形的内角和是180(n−2)°180(n-2)°180(n−2)°
我们选取一个点为起始点向别的点连线分割三角形,显然邻近两点无法分割出,从任意方向的第三个点开始,每次与点的连线都可以分割出一个三角形,三角形总数是n−2n-2n−2,所以得证。
(2)证明:任意凸nnn边形的的外交和为360°360°360°
每个外角即内角的补角,所以和为∑i=1n180−αi=180n−180(n−2)=360,αi\sum_{i=1}^{n}180-\alpha_{i}=180n-180(n-2)=360,\alpha_{i}∑i=1n180−αi=180n−180(n−2)=360,αi为其中一个内角
现在开始证明:
由于相切,那么∠OBC=∠OAC=180°→∠BOA+∠BCA=180°\angle OBC=\angle OAC=180°\rightarrow\angle BOA+\angle BCA=180°∠OBC=∠OAC=180°→∠BOA+∠BCA=180°
设每个圆的这样的圆心角为α\alphaα,对应的多边形的内角为β\betaβ
那么∑i=1nαi+βi=180n\sum_{i=1}^{n}{\alpha_{i}+\beta_{i}}=180n∑i=1nαi+βi=180n
又nnn边形内角和为180(n−2)180(n-2)180(n−2)
所以∑i=1nαi=180n−180(n−2)=360\sum_{i=1}^{n}\alpha_{i}=180n-180(n-2)=360∑i=1nαi=180n−180(n−2)=360
所以所有的圆弧加起来是一个圆的周长,得证。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const double eps=1e-10,pi=acos(-1);
int cmp(double a,double b)
{
if(fabs(a-b)<eps) return 0;
else if(a-b>eps) return 1;
return -1;
}
struct vec
{
double x,y;
bool operator==(const vec& a) const {return (x-a.x)<eps&&(y-a.y)<eps;}
vec operator+(const vec& a) const {return (vec){x+a.x,y+a.y};}
vec operator-(const vec& a) const {return (vec){x-a.x,y-a.y};}
vec operator*(const double& k) const {return (vec){x*k,y*k};}
vec operator/(const double& k) const {return (vec){x/k,y/k};}
double operator^(const vec& a) const {return x*a.y-y*a.x;}//获得叉积的模
double operator*(const vec& a) const {return x*a.x+y*a.y;}
vec operator*(const pair<int,int>&a) const {return (vec){x*a.first,y*a.first};}
friend istream& operator>>(istream& o,const vec& a)
{
scanf("%lf%lf",&a.x,&a.y);
return o;
}
friend ostream& operator<<(ostream& o,const vec& a)
{
printf("%.10lf %.10lf\n",a.x,a.y);
return o;
}
};
struct line
{
vec base,a,b;
};
bool rui(const vec& a,const vec& b){return a*b>eps;}
bool zhi(const vec& a,const vec& b){return fabs(a*b)<eps;}
bool dun(const vec& a,const vec& b){return a*b<-eps;}
bool operator!=(const vec& a,const vec& b){return !(a==b);}
double S(const vec& a,const vec& b){return fabs(a^b)/2;}
vec operator*(const double& k,const vec &a){return (vec){k*a.x,k*a.y};}
vec operator*(const pair<int,int>&a,const vec& b){return b*a;}
double getlen(const vec& a){return sqrt(a.x*a.x+a.y*a.y);}
double getangle(const vec& a,const vec& b){return acos(a*b/(getlen(a)*getlen(b)));}
vec getvertical(const vec& a){return (vec){a.y,-a.x};}
vec getsingle(const vec& a){return a/getlen(a);}
vec rotate(const vec& a,double k){return (vec){a.x*cos(k)-a.y*sin(k),a.x*sin(k)+a.y*cos(k)};}
line trans(const vec& a,const vec& b){return (line){getsingle(b-a),a,b};}
line trans(double a,double b,double x,double y){return (line){getsingle((vec){x-a,y-b}),(vec){a,b},(vec){x,y}};}
int n,cnt;
vector<vec>v(40005),s(40005),p(5);
double a,b,r,len1,len2;
inline void solve(int k)
{
double theta;
vec mid; cin>>mid; scanf("%lf",&theta);
p[1]=(vec){len1,len2};p[2]=(vec){len1,-len2};
p[3]=(vec){-len1,len2};p[4]=(vec){-len1,-len2};
for(int i=4*(k-1)+1;i<=4*k;i++) v[i]=rotate(p[i-4*(k-1)],theta)+mid;
}
int main()
{
scanf("%d%lf%lf%lf",&n,&b,&a,&r);
len1=a/2-r,len2=b/2-r;
for(int i=1;i<=n;i++) solve(i); n<<=2;
sort(v.begin()+1,v.begin()+1+n,[](const vec& temp1,const vec& temp2){
if(cmp(temp1.x,temp2.x)==0) return cmp(temp1.y,temp2.y)<1;
return cmp(temp1.x,temp2.x)<1;
});
sort(v.begin()+2,v.begin()+1+n,[](const vec& temp1,const vec& temp2){
double k=(temp1-v[1])^(temp2-v[1]);
if(cmp(k,0)==0) return cmp(getlen(temp1-v[1]),getlen(temp2-v[1]))<1;
return cmp(k,0)==1;
});
for(int i=1;i<=n;i++)
{
while(cnt>1&&cmp((s[cnt]-s[cnt-1])^(v[i]-s[cnt]),0)<1) cnt--;
s[++cnt]=v[i];
}
double ans=2*pi*r;
for(int i=1;i<=cnt;i++) ans+=getlen(s[i]-s[i%cnt+1]);
printf("%.2lf",ans);
return 0;
for(int i=1;i<=cnt;i++) ans+=getlen(s[i]-s[i%cnt+1]);
printf("%.2lf",ans);
return 0;
}