P3829 [SHOI2012]信用卡凸包

思路

注意到结果就是每个信用卡边上的四个圆心的凸包周长+一个圆的周长

然后就好做了

注意平行时把距离小的排在前面,栈中至少要有1个元素(top>1),凸包中如果存在叉积为0的点也要pop,否则可能会错。

几个简单的向量的式子

\[a*b=(x_1y_1+ x_2y_2) \]

\[a\times b=(x_1y_2- x_2y_1) \]

逆时针旋转\(\theta\)

\[x'=xcos\theta-ysin\theta\\ y'=xsin\theta+ycos\theta \]

代码

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
struct Vec{
    double x,y;
	Vec(){};
	Vec(double xx,double yy){
		x=xx;
		y=yy;
	}
	double mul(Vec b){
		return x*b.x+y*b.y;
	}
	double cross(Vec b){
		return x*b.y-y*b.x;
	}
	Vec rev(double seta){
		return Vec(x*cos(seta)-y*sin(seta),x*sin(seta)+y*cos(seta));
	}
};
struct Point{
	double x,y;
	Point(){};
	Point(double xx,double yy){
		x=xx;
		y=yy;
	}
	Point operator + (Point b){
		return Point(x+b.x,y+b.y);
	} 
	Point operator + (Vec b){
		return Point(x+b.x,y+b.y);
	} 
	Vec operator - (Point b){//b-a a->b
		return Vec(b.x-x,b.y-y);
	}
	Point rev(Point b,double seta){//a 绕 b
		return b+((Point(x,y))-b).rev(seta);
	}
	double dist(Point a){
		return sqrt((x-a.x)*(x-a.x)+(y-a.y)*(y-a.y));
	}
};
struct Stack{
	int data[400100],topx=0;
	void push(int x){
		data[++topx]=x;
	}
	void pop(void){
		topx--;
	}
	int top(void){
		return data[topx];
	}
	int Setop(void){
		return data[topx-1];
	}
};
Point a[400100];
Stack S;
bool cmp(Point x,Point y){
    return (x-a[1]).cross(y-a[1])>0||((x-a[1]).cross(y-a[1])==0&&x.dist(a[1])>y.dist(a[1]));
}
int n,cnt;
double ax,bx,rx,ans=0;
int main(){
	scanf("%d",&n);
	scanf("%lf %lf %lf",&ax,&bx,&rx);
	for(int i=1;i<=n;i++){
		double x,y,seta;
		scanf("%lf %lf %lf",&x,&y,&seta);
		a[++cnt]=Point(x-bx/2+rx,y+ax/2-rx).rev(Point(x,y),seta);
		a[++cnt]=Point(x-bx/2+rx,y-ax/2+rx).rev(Point(x,y),seta);
		a[++cnt]=Point(x+bx/2-rx,y+ax/2-rx).rev(Point(x,y),seta);
		a[++cnt]=Point(x+bx/2-rx,y-ax/2+rx).rev(Point(x,y),seta);
	}
	// for(int i=1;i<=cnt;i++)
	// 	printf("%lf %lf\n",a[i].x,a[i].y);
	int pos=1;
	for(int i=2;i<=cnt;i++)
		if(a[i].x<a[pos].x||(a[i].x==a[pos].x&&a[i].y<a[pos].y))
			pos=i;
	swap(a[1],a[pos]);
	sort(a+2,a+cnt+1,cmp);
	S.push(1);
	S.push(2);
	for(int i=3;i<=cnt;i++){
		while(S.topx>0&&(a[S.Setop()]-a[S.top()]).cross(a[S.Setop()]-a[i])<=0){
			S.pop();
		}
		S.push(i);
	}
	int tt=S.top();
	while(S.topx>1){
		ans+=a[S.top()].dist(a[S.Setop()]);
		S.pop();
	}
	ans+=a[S.top()].dist(a[tt]);
	ans+=2*acos(-1.0)*rx;
	printf("%.2lf\n",ans);
    return 0;
}
posted @ 2019-04-03 12:27  dreagonm  阅读(173)  评论(0编辑  收藏  举报