您的位置:首页 > 其它

几何模板

2008-12-08 12:16 113 查看
花了些时间准备acm的比赛,现在比赛结束有一段时间了,忙着上自习、做实验。有空就看看linux的书,至于算法,很久没有碰了。昨天刚想回toj做几个题,想不到传来toj系统维护的消息。

回顾比赛,计算几何的东西基本没有用到,这个不过这个模板上的线段树还是发挥了点作用。把模板传上来,算是一个阶段性的总结。也希望大牛多给我指出些不对的地方。

/*

*常量定义

*/

const double INF=1e200;

const double EPS=1e-7;

const double PI =acos(-1);

/*

*点的定义

*/

struct PT

{

double x,y;

PT(){}

PT(double xx,double yy)//构造函数

{

x=xx,y=yy;

return;

}

};

/*

*线段的定义

*/

struct SEG

{

PT st,end;

int len;

};

/*

*圆的定义

*/

struct CIR

{

double x,y,r;

CIR(){}

CIR(double xx,double yy,double rr)

{

x=xx,y=yy,r=rr;

return;

}

};

/*

*符号函数

*/

inline int sign(double a)

{

if(fabs(a)<EPS)

return 0;

return a>EPS?1:-1;

}

/*

*叉积

*/

inline int crossP(PT &a,PT &b,PT &c)

//cross product of ab and ac

{

return (c.x-a.x)*(b.y-a.y)-(b.x-a.x)*(c.y-a.y);

}

inline double crossP2(const PT &a,const PT &b,const PT &c,const PT &d)

//cross product of ab and cd

{

return (b.x-a.x)*(d.y-c.y)-(b.y-a.y)*(d.x-c.x);

}

/*

*点积

*/

inline double dotP(PT &a,PT &b,PT &c)

{

return (c.x-a.x)*(b.x-a.x)+(c.y-a.y)*(b.y-a.y);

}

/*

*两点间距离

*/

inline int dis(PT a,PT b)

{

return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));

}

/*

*点到线段的距离

*/

double dis2seg(PT pt,PT st,PT end)

{

if(dotP(st,end,pt)*dotP(end,st,pt)<0)

return min(dis(pt,st),dis(pt,end));

return fabs(crossP(st,end,pt)/dis(st,end));

}

/*

*已知圆上三点求该圆

*pt1,pt2,pt3是圆上三点

*cen是圆心的引用,返回半径

*/

double getRadiusBy3PT(PT pt1,PT pt2,PT pt3,PT &cen)

{

double a1,a2,b1,b2,c1,c2;

a1=2*(pt2.x-pt1.x);

a2=2*(pt3.x-pt1.x);

b1=2*(pt2.y-pt1.y);

b2=2*(pt3.y-pt1.y);

c1=pt2.x*pt2.x+pt2.y*pt2.y-pt1.x*pt1.x-pt1.y*pt1.y;

c2=pt3.x*pt3.x+pt3.y*pt3.y-pt1.x*pt1.x-pt1.y*pt1.y;

cen.y=(a2*c1-a1*c2)/(a2*b1-a1*b2);

cen.x=(b2*c1-b1*c2)/(b2*a1-b1*a2);

return dis(pt1,c);

}

/*

*两圆相交部分的面积

*不相交返回0

*/

double CircleIntersectionArea(CIR a,CIR b)

{

double len=dis(a,b);

if(sign(len-a.r-b.r)>=0 || a.r<EPS || b.r< EPS)

return 0;

else if(sign(a.r+len-b.r)<=0)

return PI*a.r*a.r;

else if(sign(b.r+len-a.r)<=0)

return PI*b.r*b.r;

double ang1=2*acos((a.r*a.r+len*len-b.r*b.r)/(2*a.r*len));

double ang2=2*acos((b.r*b.r+len*len-a.r*a.r)/(2*b.r*len));

double re=a.r*a.r*ang1*0.5-0.5*a.r*a.r*sin(ang1);

re+=b.r*b.r*ang2*0.5-0.5*b.r*b.r*sin(ang2);

return re;

}

/*

*判断线段是否相交

*端点相交返回false

*如果需要,把<改为<=

*那么,共线也会返回true

*/

inline bool intersect(PT s1,PT e1,PT s2,PT e2)

{

return((max(s1.x,e1.x)>=min(s2.x,e2.x)) &&

(max(s2.x,e2.x)>=min(s1.x,e1.x)) &&

(max(s1.y,e1.y)>=min(s2.y,e2.y)) &&

(max(s2.y,e2.y)>=min(s1.y,e1.y)) &&

(crossP(s1,e1,s2)*crossP(s1,e1,e2)<0) &&

(crossP(s2,e2,s1)*crossP(s2,e2,e1)<0));

}

/*

判断线段是否严格相交

*/

int strictcross(point p1, point p2, point p3, point p4) {

T a, b, c, d;

a=(p3.y-p2.y)*(p1.x-p2.x)-(p1.y-p2.y)*(p3.x-p2.x);

b=(p4.y-p2.y)*(p1.x-p2.x)-(p1.y-p2.y)*(p4.x-p2.x);

c=(p1.y-p4.y)*(p3.x-p4.x)-(p3.y-p4.y)*(p1.x-p4.x);

d=(p2.y-p4.y)*(p3.x-p4.x)-(p3.y-p4.y)*(p2.x-p4.x);

return a*b<0 && c*d<0;

}

/*

*判断简单多边形是否是凸多边形

*vpt[]:所有点

*n:点的数量

*/

bool isprotude(PT vpt[],int n)

{

int t,tt,pre;

for(t=0;t<n;t++)

{

tt=0;

while(pre=sign(crossP(vpt[t],vpt[(t+1)%n],vpt[(t+2+tt)%n])),pre==0)

tt++;

for(;tt<n-2;tt++)

{

double d=crossP(vpt[t],vpt[(t+1)%n],vpt[(t+2+tt)%n]);

if(sign(d)==0)

continue;

if(sign(d)!=pre)

return false;

}

}

return true;

}

/*

*判断点是否在凸多边形内部

*在边上为false

*for convex polygen only!

*/

bool inPoly(PT vpt[],int n,PT &pt)

{

int t;

PT st,end;

int dr=sign(crossP(vpt[0],vpt[1],pt));

for(t=1;t<n;t++)

{

st=vpt[t];

end=vpt[(t+1)%n];

if(sign(crossP(st,end,pt))!=dr)

return false;

}

return true;

}

/*

*Graham法求凸包

*双链法扫描

*pt[]:所有点

*n:pt[]中点的个数

*ans[]:用于返回凸包中的点

*返回凸包中点的个数

*默认逆时针时针方向

*/

int graham(int n,PT pt[],PT ans[])

{

int stk[MAX];

bool vis[MAX];

int t,p,ps,pans=0;

sort(pt,pt+n,cmp);

memset(vis,false,sizeof(vis));

stk[0]=0;

stk[1]=1;

vis[1]=true;

ps=p=2;

while(p<n)

{

if(ps<2 || crossP(pt[stk[ps-2]],pt[stk[ps-1]],pt[p])>=0)

//or crossP()<=0 to be clockwise

//if points in stk is not enough

//or pt[p] is on the left side or on segmemt

//push pt[p] into stack

//and mark pt[p] as visited

{

stk[ps++]=p++;

vis[p]=true;

}

else

//pop the top point

//and mark it as unvisited

vis[stk[--ps]]=false;

}

for(t=0;t<ps;t++)

ans[pans++]=pt[stk[t]];

vis[n-1]=false;//second travle start here

ps=0;//clear the stack to start new travle

for(p=n-1;p>=0;p--)

if(!vis[p])

{

stk[ps++]=p;

if(ps==2)//push first 2 points

break;

}

p--;//next point

while(p>=0)//mark is not needed any more

{

if(vis[p])

{

p--;

continue;

}

if(ps<2 || crossP(pt[stk[ps-2]],pt[stk[ps-1]],pt[p])>=0)

//or crossP()<=0 to be clockwise

stk[ps++]=p--;

else

--ps;

}

for(t=1;t<ps-1;t++)

ans[pans++]=pt[stk[t]];

return pans;

}

/*

旋转卡壳求最远点距离

*/

double RotatingCaliper(const int &n,PT pt[])

{

double re=0;

int t=0,tt=1;

while(sign(crossP2(pt[t],pt[t+1],pt[tt],pt[tt+1]))==1)

tt++;

while);<=n)

{

int tmp=sign(crossP2(pt[t%n],pt[(t+1)%n],pt[tt%n],pt[(tt+1)%n]));

if(tmp==1)

tt=(tt+1)%n;

else if(tmp==-1)

t++;

else

{

t++;

continue;

}

double d=dis(pt[t],pt[tt]);

if(d>re)

re=d;

}

return re;

}

/*

*线段树,离散化

*/

struct Line

{

double x,tp,bt;

bool  left;

}line[2005];

double y[2005];

int num,ny;//离散化前后y[]的大小

inline int find(double a)//二分查找对应的离散值

{

int low=0,high=ny-1,mid;

while(low<=high)

{

mid=(low+high)/2;

if(a==y[mid])

return mid;

else if(a<y[mid])

high=mid;

else

low=mid+1;

}

return -1;

}

struct node

{

int st,end,c;//c是区间被覆盖次数

double m;//m是测度

node *ls,*rs;

}* root;

node * build(int st,int end)

{

node *p=new node;

p->st=st;

p->end=end;

p->c=0;

p->m=0;

if(st+1<end)//注意一下这里

{

int mid=(st+end)/2;

p->ls=build(st,mid);

p->rs=build(mid,end);

}

else

p->ls=p->rs=NULL;

return p;

}

void init(node *p)//初始化

{

p->c=0;

p->m=0;

if(p->ls!=NULL)

init(p->ls);

if(p->rs!=NULL)

init(p->rs);

return;

}

inline void update(node *p)//更新测度

{

if(p->c>0)

p->m=y[p->end]-y[p->st];

else if(p->st+1==p->end)

p->m=0;

else

p->m=p->ls->m+p->rs->m;

return;

}

void ins(node *p,int st,int end)

{

if(st<=p->st && p->end<=end)

{

p->c++;

update(p);

return;

}

int mid=(p->st + p->end)/2;

if(p->ls!=NULL)

{

ins(p->ls,st,end);

update(p);

}

if(p->rs!=NULL)

{

ins(p->rs,st,end);

update(p);

}

return;

}

void del(node *p,int st,int end)

{

if(st<=p->st && p->end<=end)

{

p->c--;

update(p);

return;

}

if(p->ls!=NULL)

{

del(p->ls,st,end);

update(p);

}

if(p->rs!=NULL )

{

del(p->rs,st,end);

update(p);

}

return;

}

/*

*树状数组,有待完善

*/

const int MAX=32005*3;//大一点好

struct node

{

int st,end,c;

}T[MAX];

inline int ls(int k)

{

return 2*k;

}

inline int rs(int k)

{

return 2*k+1;

}

void build(int p,int st,int end)//建树

{

T[p].st=st;

T[p].end=end;

T[p].c=0;

if(st<end)

{

int mid=(st+end)/2;

build(ls(p),st,mid);

build(rs(p),mid+1,end);

}

return;

}

void ins(int p,int k)//插入一个点

{

if(T[p].st<=k && k<=T[p].end)

{

T[p].c++;

if(T[p].st<T[p].end)

{

ins(ls(p),k);

ins(rs(p),k);

}

}

return;

}

int ask(int p,int st,int end)//询问一个区间内有几个点

{

if(st<=T[p].st && T[p].end<=end)

return T[p].c;

else if(st>T[p].end || end<T[p].st)

return 0;

else

return ask(ls(p),st,end)+ask(rs(p),st,end);

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: