poj1113 凸包

时间:2022-03-13 10:43:47

result=对所有点凸包周长+pi*2*L

WA了一次,被Pi的精度坑了

以后注意Pi尽可能搞精确一点。Pi=3.14还是不够用

Code:

 #include<vector>
#include<list>
#include<map>
#include<set>
#include<deque>
#include<queue>
#include<stack>
#include<bitset>
#include<algorithm>
#include<functional>
#include<numeric>
#include<utility>
#include<iostream>
#include<sstream>
#include<iomanip>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cctype>
#include<string>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<ctime>
#include<climits>
#include<complex>
#define mp make_pair
#define pb push_back
using namespace std;
const double eps=1e-;//精度
const double pi=acos(-1.0);//π
const double inf=1e20;//无穷大
const int maxp=;//最大点数 /*
判断d是否在精度内等于0
*/
int dblcmp(double d)
{
if (fabs(d)<eps)return ;
return d>eps?:-;
}
/*
求x的平方
*/
inline double sqr(double x){return x*x;}
/*
点/向量
*/
struct point
{
double x,y;
point(){}
point(double _x,double _y):x(_x),y(_y){};
//读入一个点
void input()
{
scanf("%lf%lf",&x,&y);
}
//输出一个点
void output()
{
printf("%.2f %.2f\n",x,y);
}
//判断两点是否相等
bool operator==(point a)const
{
return dblcmp(a.x-x)==&&dblcmp(a.y-y)==;
}
//判断两点大小
bool operator<(point a)const
{
return dblcmp(a.x-x)==?dblcmp(y-a.y)<:x<a.x;
}
//点到源点的距离/向量的长度
double len()
{
return hypot(x,y);
}
//点到源点距离的平方
double len2()
{
return x*x+y*y;
}
//两点间的距离
double distance(point p)
{
return hypot(x-p.x,y-p.y);
}
//向量加
point add(point p)
{
return point(x+p.x,y+p.y);
}
//向量减
point sub(point p)
{
return point(x-p.x,y-p.y);
}
//向量乘
point mul(double b)
{
return point(x*b,y*b);
}
//向量除
point div(double b)
{
return point(x/b,y/b);
}
//点乘
double dot(point p)
{
return x*p.x+y*p.y;
}
//叉乘
double det(point p)
{
return x*p.y-y*p.x;
}
//XXXXXXX
double rad(point a,point b)
{
point p=*this;
return fabs(atan2(fabs(a.sub(p).det(b.sub(p))),a.sub(p).dot(b.sub(p))));
}
//截取长度r
point trunc(double r)
{
double l=len();
if (!dblcmp(l))return *this;
r/=l;
return point(x*r,y*r);
}
//左转90度
point rotleft()
{
return point(-y,x);
}
//右转90度
point rotright()
{
return point(y,-x);
}
//绕点p逆时针旋转angle角度
point rotate(point p,double angle)
{
point v=this->sub(p);
double c=cos(angle),s=sin(angle);
return point(p.x+v.x*c-v.y*s,p.y+v.x*s+v.y*c);
}
};
/*
线段/直线
*/
struct line
{
point a,b;
line(){}
line(point _a,point _b)
{
a=_a;
b=_b;
}
//判断线段相等
bool operator==(line v)
{
return (a==v.a)&&(b==v.b);
}
//点p做倾斜角为angle的射线
line(point p,double angle)
{
a=p;
if (dblcmp(angle-pi/)==)
{
b=a.add(point(,));
}
else
{
b=a.add(point(,tan(angle)));
}
}
//直线一般式ax+by+c=0
line(double _a,double _b,double _c)
{
if (dblcmp(_a)==)
{
a=point(,-_c/_b);
b=point(,-_c/_b);
}
else if (dblcmp(_b)==)
{
a=point(-_c/_a,);
b=point(-_c/_a,);
}
else
{
a=point(,-_c/_b);
b=point(,(-_c-_a)/_b);
}
}
//读入一个线段
void input()
{
a.input();
b.input();
}
//校准线段两点
void adjust()
{
if (b<a)swap(a,b);
}
//线段长度
double length()
{
return a.distance(b);
}
//直线倾斜角 0<=angle<180
double angle()
{
double k=atan2(b.y-a.y,b.x-a.x);
if (dblcmp(k)<)k+=pi;
if (dblcmp(k-pi)==)k-=pi;
return k;
}
//点和线段关系
//1 在逆时针
//2 在顺时针
//3 平行
int relation(point p)
{
int c=dblcmp(p.sub(a).det(b.sub(a)));
if (c<)return ;
if (c>)return ;
return ;
}
//点是否在线段上
bool pointonseg(point p)
{
return dblcmp(p.sub(a).det(b.sub(a)))==&&dblcmp(p.sub(a).dot(p.sub(b)))<=;
}
//两线是否平行
bool parallel(line v)
{
return dblcmp(b.sub(a).det(v.b.sub(v.a)))==;
}
//线段和线段关系
//0 不相交
//1 非规范相交
//2 规范相交
int segcrossseg(line v)
{
int d1=dblcmp(b.sub(a).det(v.a.sub(a)));
int d2=dblcmp(b.sub(a).det(v.b.sub(a)));
int d3=dblcmp(v.b.sub(v.a).det(a.sub(v.a)));
int d4=dblcmp(v.b.sub(v.a).det(b.sub(v.a)));
if ((d1^d2)==-&&(d3^d4)==-)return ;
return (d1==&&dblcmp(v.a.sub(a).dot(v.a.sub(b)))<=||
d2==&&dblcmp(v.b.sub(a).dot(v.b.sub(b)))<=||
d3==&&dblcmp(a.sub(v.a).dot(a.sub(v.b)))<=||
d4==&&dblcmp(b.sub(v.a).dot(b.sub(v.b)))<=);
}
//线段和直线v关系
int linecrossseg(line v)//*this seg v line
{
int d1=dblcmp(b.sub(a).det(v.a.sub(a)));
int d2=dblcmp(b.sub(a).det(v.b.sub(a)));
if ((d1^d2)==-)return ;
return (d1==||d2==);
}
//直线和直线关系
//0 平行
//1 重合
//2 相交
int linecrossline(line v)
{
if ((*this).parallel(v))
{
return v.relation(a)==;
}
return ;
}
//求两线交点
point crosspoint(line v)
{
double a1=v.b.sub(v.a).det(a.sub(v.a));
double a2=v.b.sub(v.a).det(b.sub(v.a));
return point((a.x*a2-b.x*a1)/(a2-a1),(a.y*a2-b.y*a1)/(a2-a1));
}
//点p到直线的距离
double dispointtoline(point p)
{
return fabs(p.sub(a).det(b.sub(a)))/length();
}
//点p到线段的距离
double dispointtoseg(point p)
{
if (dblcmp(p.sub(b).dot(a.sub(b)))<||dblcmp(p.sub(a).dot(b.sub(a)))<)
{
return min(p.distance(a),p.distance(b));
}
return dispointtoline(p);
}
//XXXXXXXX
point lineprog(point p)
{
return a.add(b.sub(a).mul(b.sub(a).dot(p.sub(a))/b.sub(a).len2()));
}
//点p关于直线的对称点
point symmetrypoint(point p)
{
point q=lineprog(p);
return point(*q.x-p.x,*q.y-p.y);
}
}; /*
多边形
*/
struct polygon
{
int n;//点个数
point p[maxp];//顶点
//读入一个多边形
void input(int n)
{
for (int i=;i<n;i++)
{
p[i].input();
}
}
struct cmp
{
point p;
cmp(const point &p0){p=p0;}
bool operator()(const point &aa,const point &bb)
{
point a=aa,b=bb;
int d=dblcmp(a.sub(p).det(b.sub(p)));
if (d==)
{
return dblcmp(a.distance(p)-b.distance(p))<;
}
return d>;
}
};
void norm()
{
point mi=p[];
for (int i=;i<n;i++)mi=min(mi,p[i]);
sort(p,p+n,cmp(mi));
}
//求凸包存入多边形convex
void getconvex(polygon &convex)
{
int i,j,k;
sort(p,p+n);
convex.n=n;
for (i=;i<min(n,);i++)
{
convex.p[i]=p[i];
}
if (n<=)return;
int &top=convex.n;
top=;
for (i=;i<n;i++)
{
while (top&&convex.p[top].sub(p[i]).det(convex.p[top-].sub(p[i]))<=)
top--;
convex.p[++top]=p[i];
}
int temp=top;
convex.p[++top]=p[n-];
for (i=n-;i>=;i--)
{
while (top!=temp&&convex.p[top].sub(p[i]).det(convex.p[top-].sub(p[i]))<=)
top--;
convex.p[++top]=p[i];
}
}
//取得周长
double getcircumference()
{
double sm=;
int i;
for (i=;i<n;i++)
{
sm+=p[i].distance(p[(i+)%n]);
//printf("%.2f\n",sm);
}
return sm;
}
}; struct polygon P,R;
int N,L;
double sum=; int main()
{
//freopen("in2.txt","r",stdin); cin>>N>>L;
P.n=N;
P.input(N);
P.getconvex(R); sum=R.getcircumference();
//cout<<R.n<<endl;
//for (int i=0;i<R.n;i++)
// printf("%.2f %.2f\n",R.p[i].x,R.p[i].y); sum+=3.14159265358979723846*(double)L*;
printf("%.0f\n",sum); return ;
}

最基础的凸包算法:卷包裹算法。基本思想就好像把所有的点比作一堆钉子,拿一根绳子捆在最左边的点上,然后按顺时针or逆时针围一圈

http://www.cnblogs.com/Booble/archive/2011/02/28/1967179.html

------------------------我是傲傲傲娇哒分割线---------------------------------

求凸包的Andrew算法:

设所有点在平面坐标系上,从最左下角的点开始,从左到右来一次,再从右到左来一次,最后回到起点。

把所有点按x和y坐标作为关键字从小到大排序(x优先)。先把第一个点和第二个点加入凸包。

在扫描的过程中,当前凸包的前进方向即倒数第二个入凸包的点->倒数第一个入凸包的点这一向量。

若新点在凸包前进方向的左边则继续,否则依次删除最近加入凸包的点,直到新点在左边为止。

eg:

STEP1:当前已经加入了这些点:

poj1113   凸包

STEP2:加入了点4

poj1113   凸包

STEP3:这时再想加5的时候发现5在向量3->4的右边,加不了了-_-||

     于是把4删掉。

STEP4:这时5在向量2->3的左边了。加5

    PS:如果删掉了还是在右边的话就接着删

poj1113   凸包

判断新点在某个向量的左边还是右边可以用叉乘。

poj1113   凸包