计算几何
1.凸包
凸包可以想象成把一些散落在纸上的点用一个橡皮筋勒住,围成的多边形。
andrew算法
将散落的点按x,为第一,y为第二排序。先取正向取上面的点,然后再反向去下面的点围成的图形就是凸包。
P3829 [SHOI2012]信用卡凸包
#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
#define x first
#define y second
const int maxn =1e4+10;
const double eps=1e-8;
const double pi = acos(-1);
typedef pair<double,double>PDD;
int cnt=0;
PDD p[maxn<<2];
bool used[maxn<<2];
int stk[maxn<<2];
int sign(double x){判断浮点数的正负
if(fabs(x)<eps) return 0;
return x<0?-1:1;
}
PDD Rotate(double x,double y,double o){//将(x,y)顺时旋转o度的点
return {x*cos(o)+y*sin(o),y*cos(o)-x*sin(o)};
}
PDD operator-(PDD a,PDD b){
return {a.x-b.x,a.y-b.y};
}
double cross(PDD a,PDD b){//叉乘
return a.x*b.y-a.y*b.x;
}
double area(PDD p,PDD b,PDD a){//由p指向b,a的线段组成的面积,由pb转向pa,大于零pa在pb左侧,反之在右侧
return cross(b-p,a-p);
}
double get_dis(PDD a,PDD b){//返回a,b点之间的距离
double dx=a.x-b.x;
double dy=a.y-b.y;
return sqrt(dx*dx+dy*dy);
}
double andrew(){
sort(p,p+cnt);
int top=0,t;
for(int i = 0; i < cnt ; i++){
while(top>=2&&(t=sign(area(p[stk[top-1]],p[stk[top]],p[i])))>0){
used[stk[top--]]=false;
}
stk[++top]=i;
used[i]=true;
}used[0]=false;
for(int i = cnt-1; i >= 0; i--){
if(used[i]) continue;
while(top>=2&&sign(area(p[stk[top-1]],p[stk[top]],p[i]))>0)
top--;
stk[++top]=i;
}
double res=0;
for(int i = 2; i <= top ; i++){
res+=get_dis(p[stk[i]],p[stk[i-1]]);
}return res;
}
int main()
{
int n;scanf("%d",&n);
double a,b,r;scanf("%lf%lf%lf",&a,&b,&r);
a=a/2-r,b=b/2-r;
int dx[4]={1,1,-1,-1};
int dy[4]={-1,1,-1,1};
while(n--){
double x,y,o;scanf("%lf%lf%lf",&x,&y,&o);
for(int i = 0 ; i < 4; i++){
auto t=Rotate(b*dx[i],a*dy[i],-o);
p[cnt++]={x+t.x,y+t.y};
}
}
double res=2*pi*r;
res+=andrew();
printf("%.2lf\n",res);
return 0;
}
这里在处理上面的点时有两种写法
for(int i = 0; i < cnt ; i++){
while(top>=2&&sign(area(p[stk[top-1]],p[stk[top]],p[i]))>0){
used[stk[top--]]=false;
}
stk[++top]=i;
used[i]=true;
}used[0]=false;
for(int i = cnt-1; i >= 0; i--){
if(used[i]) continue;
while(top>=2&&sign(area(p[stk[top-1]],p[stk[top]],p[i]))>0)
top--;
stk[++top]=i;
}
for(int i = 0; i < cnt ; i++){
while(top>=2&&(t=sign(area(p[stk[top-1]],p[stk[top]],p[i])))>=0){
if(t>0) used[stk[top]]=false;
top--;
}
stk[++top]=i;
used[i]=true;
}used[0]=false;
for(int i = cnt-1; i >= 0; i--){
if(used[i]) continue;
while(top>=2&&sign(area(p[stk[top-1]],p[stk[top]],p[i]))>=0)
top--;
stk[++top]=i;
}