ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

题解 P3829 [SHOI2012]信用卡凸包

2022-05-02 08:01:43  阅读:147  来源: 互联网

标签:题解 top 凸包 second pair stk SHOI2012 first


1.题意

给一些相同的信用卡,本质上是圆,求以所有信用卡的圆心为点集,求这个点集的凸包的周长。

2.思路

这题事实上没那么难。

不会凸包或者计算几何的,去看https://www.luogu.com.cn/problem/P2742,或者看看https://oi-wiki.org//geometry/的讲解。

事实上,如果信用卡是矩形,那么直接可以把矩形的所有点抽出来,跑一个凸包算法即可。这道题的难点在于信用卡是圆,而我们取出的点就有可能是一个 $\frac{1}{4}$ 圆了,也就无法正常使用凸包算法了。

说白了,我们要求出形如下图的围住的线的长度。

 

 

观察上图,容易发现,所有圆与线重合的部位就是这个圆的切线。而我们已知,圆的切线垂直于过其切点的半径。

观察每一个圆,发现重要的规律。

 

 

正如上如所示,$\alpha$ 为圆心角,因为切线垂直,发现一个对角互补四边形!

而 $\beta$ ,恰好是外角,所以 $\alpha = \beta$。

又因为多边形的外角和是 $360°$,所以 $\beta$ 加起来就是 $360°$。

所以,$\alpha$ 加起来也是 $360°$。

整个图中,所有圆都是相等的,所以,我们可以看出,所有圆连接切线而构成的扇形拼在一起就是整整一个圆。

所以问题就解决了一半,圆弧的总长就是 $2πr$ 。

剩下的问题就是,求一下所有直边的长度。

 

 

根据矩形平移,我们非常容易地得出,所有圆心点求一个凸包就是所有直边的长度。

直边长加上圆的周长,即为答案,至此,本题做完。

3.代码

 

#include<bits/stdc++.h>
using namespace std;
int n,tx[]={1,1,-1,-1},ty[]={1,-1,1,-1},cnt,stk[100005],top;
bool vis[100005];
double a,b,r,xx,yy,zz,res;
pair<double,double> q[100005];
pair<double,double> rotate(pair<double,double> a,double b){
	return {a.first*cos(b)+a.second*sin(b),-a.first*sin(b)+a.second*cos(b)};
}
pair<double,double> operator-(pair<double,double> a,pair<double,double> b){
    return {a.first-b.first,a.second-b.second};
}
double cross(pair<double,double> a,pair<double,double> b){
	return a.first*b.second-a.second*b.first;
}
double area(pair<double,double> a,pair<double,double> b,pair<double,double> c){
    return cross(b-a,c-a);
}
double get_dist(pair<double,double> a,pair<double,double> b){
	double dx=a.first-b.first,dy=a.second-b.second;
    return sqrt(dx*dx+dy*dy);
}
int main(){
	scanf("%d%lf%lf%lf",&n,&a,&b,&r);
	a=a/2-r;
	b=b/2-r;
	for(int i=1;i<=n;i++){
		scanf("%lf%lf%lf",&xx,&yy,&zz);
		for(int i=0;i<4;i++){
			pair<double,double> temp=rotate({tx[i]*b,ty[i]*a},-zz);
			q[cnt++]={temp.first+xx,temp.second+yy};
		}
	}
	sort(q,q+cnt);
	for(int i=0;i<cnt;i++){
		while(top>=2&&area(q[stk[top-1]],q[stk[top]],q[i])>=0){
			vis[stk[top--]]=0;
		}
		stk[++top]=i;
		vis[i]=1;
	}
	vis[0]=0;
	for(int i=cnt-1;i>=0;i--){
		if(vis[i]){
			continue;
		}
		while(top>=2&&area(q[stk[top-1]],q[stk[top]],q[i])>=0){
			top--;
		}
		stk[++top]=i;
	}
	for(int i=2;i<=top;i++){
		res+=get_dist(q[stk[i-1]],q[stk[i]]);
	}
	printf("%.2lf",res+2*3.141592653589793*r);
	return 0;
}

  

标签:题解,top,凸包,second,pair,stk,SHOI2012,first
来源: https://www.cnblogs.com/yxysblock/p/16215006.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有