2018.10.18【洛谷P3829】【SHOI2012】信用卡凸包(凸包)

版权声明:转载请声明出处,谢谢配合。 https://blog.csdn.net/zxyoi_dreamer/article/details/83140788

传送门


解析:

开始以为要把圆弧拆成几个小的点,后来看见数据范围就放弃了。。。

然后又考虑以八边形记录每个信用卡。
又因为奇奇怪怪的精度问题跪了。。。

思路:

首先发现一个性质:在最后曲边形凸包中,圆弧的弧度和总是 2 π 2\pi

简单证明一下:可以发现,凸包上所有角肯定是由圆弧构成的,那么考虑将凸包的边两两延长相交,补全这个凸多边形。
然后发现,每个角的圆弧的圆心向两边作垂线,由于本身是凸包,这里的垂足就是边与圆弧的交点。
那么,两条垂线和边的延长线构成了一个圆内接四边形,那么这个圆心角就是凸多边形的外角。
凸多边形外角之和等于 36 0 360^\circ ,所以圆滑处理后的圆弧的总度数之和等于 2 π 2\pi ,是一个整圆。

那么就好办了,我们发现可以将最终的凸包每条边向内部平移 r r 长度,得到最终的多边形。

实际要求的就是这个多边形的周长加上一个圆的周长。

所以我们在开始的时候就直接将每个点向它所在的矩形内部移动就行了,注意向量的旋转。


代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc getchar
#define pc putchar
#define cs const

inline double getdb(){
	re double x,y=1.0;
	re char c;
	re bool f=0;
	while(!isdigit(c=gc()))if(c=='-')f=1;x=c^48;
	while(isdigit(c=gc()))x=(x*10)+(c^48);
	if(c!='.')return f?-x:x;
	while(isdigit(c=gc()))x+=(y/=10)*(c^48);
	return f?-x:x;
}

cs double PI=acos(-1);
cs double eps=1e-6;

struct Point{
	double x,y;
	Point(cs double &_x=0,cs double &_y=0):x(_x),y(_y){}
	
	friend Point operator+(cs Point &a,cs Point &b){return Point(a.x+b.x,a.y+b.y);}
	friend Point operator-(cs Point &a,cs Point &b){return Point(a.x-b.x,a.y-b.y);}
	friend Point operator*(cs Point &a,cs double &b){return Point(a.x*b,a.y*b);}
	friend Point operator/(cs Point &a,cs double &b){return Point(a.x/b,a.y/b);}
	friend double operator*(cs Point &a,cs Point &b){return a.x*b.y-b.x*a.y;}
	friend double dot(cs Point &a,cs Point &b){return a.x*b.x+a.y*b.y;}
	double norm()cs{return sqrt(dot(*this,*this));}
	friend double dist(cs Point &a,cs Point &b){return (a-b).norm();}
	friend Point rotate(cs Point &a,cs double &rad){return Point(a.x*cos(rad)-a.y*sin(rad),a.x*sin(rad)+a.y*cos(rad));}
}O;

inline int sign(cs double &x){
	return fabs(x)<eps?0:(x>0?1:-1);
}

inline bool cmp1(cs Point &a,cs Point &b){
	return sign(a.x-b.x)==0?a.y<b.y:a.x<b.x;
}

inline bool cmp2(cs Point &a,cs Point &b){
	return sign((a-O)*(b-O))==0?(a-O).norm()<(b-O).norm():sign((a-O)*(b-O))>0;
}

cs int N=10004;
struct Polygon{
	Point p[N<<2];
	int n;
	
	Polygon convex_hull(){
		sort(p+1,p+n+1,cmp1);
		O=p[1];
		sort(p+2,p+n+1,cmp2);
		int m=1;
		for(int re i=2;i<=n;++i){
			while(m>=2&&sign((p[i]-p[m-1])*(p[m]-p[m-1]))>=0)--m;
			p[++m]=p[i];
		}
		n=m;
		return *this;
	}
	
	double circuit(){
		double res=0;
		for(int re i=1;i<=n;++i)res+=dist(p[i],p[i%n+1]);
		return res;
	}
}Poly;

int tot;
double a,b,r;
Point lu,ld,ru,rd;
signed main(){
	scanf("%d",&Poly.n);
	b=getdb();
	a=getdb();
	r=getdb();
	a-=r*2;
	b-=r*2;
	lu=Point(-a/2,b/2);
	ru=Point(a/2,b/2);
	ld=Point(-a/2,-b/2);
	rd=Point(a/2,-b/2);
	for(int re i=1;i<=Poly.n;++i){
		double x=getdb(),y=getdb(),rad=getdb();
		Poly.p[++tot]=Point(x,y)+rotate(lu,rad);
		Poly.p[++tot]=Point(x,y)+rotate(ru,rad);
		Poly.p[++tot]=Point(x,y)+rotate(ld,rad);
		Poly.p[++tot]=Point(x,y)+rotate(rd,rad);
	}
	Poly.n=tot;
	Poly.convex_hull();
	double res=Poly.circuit();
	printf("%.2f",res+2*PI*r);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/zxyoi_dreamer/article/details/83140788
今日推荐