旋转卡壳法求直径

先求出凸包,时间复杂度O(n*log(n))

然后运用旋转卡壳发求出凸包的直径。

旋转卡壳法:

1.先求出y坐标最大的点为maxx,y最小的点为minn。

2.过minn,,maxx点做一条平行于x轴的直线

3.俩直线分别对minn,maxx点逆时针旋转至某一条直线与凸包的某个点相交为止。

4,用交点更新前一个点。

5,重复3-4直至目前两点都出现过为止。

6,每次旋转之后得到的两点之间的距离的最大值即为凸包的直径

原理:

第一步寻找到的一对点(minn,maxx)一定是一对对踵点。

然后旋转直线会得到另外一对对踵点。

这样一直旋转就会得到所有的对踵点。

然后凸包的直径是某个对踵点直径的距离。

#include<string.h>#include<algorithm>#include<stdlib.h>#include<iostream>#include<stdio.h>#include<vector>#define INF 1000000using namespace std;struct list{int x,y;} node[50051],tu[50051];int ts,n;int vis[50051];int len(struct list a,struct list b){int xx=a.x-b.x;int yy=a.y-b.y;return xx*xx+yy*yy;}int cmp1(struct list a,struct list b){if(a.y!=b.y)return a.y<b.y;return a.x<b.x;}int cmp2(struct list a,struct list b){int x1=a.x-node[1].x;int x2=b.x-node[1].x;int y1=a.y-node[1].y;int y2=b.y-node[1].y;if(x1*y2==x2*y1)return len(a,node[1])<len(b,node[1]);return x1*y2>x2*y1;}void push(int i){if(ts<=2){tu[ts++]=node[i];return ;}int x1=tu[ts-1].x-tu[ts-2].x;int y1=tu[ts-1].y-tu[ts-2].y;int x2=node[i].x-tu[ts-1].x;int y2=node[i].y-tu[ts-1].y;if(x1*y2>x2*y1)tu[ts++]=node[i];else ts–,push(i);}void tubao(){tu[0]=node[1];tu[1]=node[2];for(int i=3; i<=n; i++)push(i);}void diameter(){int minn,maxx;minn=maxx=0;for(int i=0; i<ts; i++){if(tu[minn].y>tu[i].y)minn=i;if(tu[maxx].y<tu[i].y)maxx=i;}int s1,s2;s1=minn;s2=maxx;int lens;lens=len(tu[s1],tu[s2]);memset(vis,0,sizeof(vis));while(vis[s1]==0||vis[s2]==0){vis[s1]=vis[s2]=1;int x1=tu[s2].x-tu[(s2+1)%ts].x;int x2=tu[(s1+1)%ts].x-tu[s1].x;int y1=tu[s2].y-tu[(s2+1)%ts].y;int y2=tu[(s1+1)%ts].y-tu[s1].y;if(y1*x2<y2*x1)s2=(s2+1)%ts;//根据叉积判断旋转直线最先碰到哪条边else s1=(s1+1)%ts;lens=max(lens,len(tu[s1],tu[s2]));}cout<<lens<<endl;}int main(){scanf("%d",&n);ts=2;for(int i=1; i<=n; i++)scanf("%d%d",&node[i].x,&node[i].y);sort(node+1,node+n+1,cmp1);sort(node+2,node+n+1,cmp2);tubao();diameter();return 0;}

创造条件,去改变生活,做生活的强者.愿你早日成为生活的强者

旋转卡壳法求直径

相关文章:

你感兴趣的文章:

标签云: