旋转卡壳小结
来源:互联网 发布:2017年最污的网络热词 编辑:程序博客网 时间:2024/05/21 07:55
这几天做了两道旋转卡壳题,做个小结。
第一题POJ2187
本题求n个点的最远点对。
首先n^2枚举肯定TLE。
考虑其他方法。
应当注意到最远点对必然在凸包上,所以首先做凸包。
接着枚举每条边,可以利用高单峰的性质,维护一个指针。然后就可以求离每条边最远的点对了。
虽然很简单,但是未能1A。
2个错误:
凸包第二个for要从n-1到1.不能到2.
取最大值手滑。
/*ID:huangta3PROG:LANG:C++*/#include <iostream>#include <cstring>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cmath>#include <list>#include <queue>#include <vector>#include <ctime>#include <set>#include <bitset>#include <deque>#include <fstream>#include <stack>#include <map>#include <utility>#include <cassert>#include <string>#include <iterator>#include <cctype>using namespace std;const int maxn=50003;int get(){ int f=0,v=0;char ch; while(!isdigit(ch=getchar()))if(ch=='-')break; if(ch=='-')f=1;else v=ch-48; while(isdigit(ch=getchar()))v=v*10+ch-48; if(f==1)return -v;else return v;}struct Tpoint{ int x,y; Tpoint(){} Tpoint(int _x,int _y){x=_x,y=_y;} void getpoint(){x=get(),y=get();}}a[maxn],P[maxn];int n;bool cmp(Tpoint a,Tpoint b){return a.x==b.x?a.y<b.y:a.x<b.x;}bool operator ==(Tpoint a,Tpoint b){return a.x==b.x&&a.y==b.y;}Tpoint operator -(Tpoint a,Tpoint b){return Tpoint(a.x-b.x,a.y-b.y);}int operator *(Tpoint a,Tpoint b){return a.x*b.y-a.y*b.x;}int dist(Tpoint a,Tpoint b){return (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y);}void init(){ n=get(); for(int i=1;i<=n;i++)a[i].getpoint(); sort(a+1,a+1+n,cmp);}void graham(){ int h=1,r=0; for(int i=1;i<=n;i++) { if(i!=1&&a[i]==a[i-1])continue; while(h<r&&(P[r]-P[r-1])*(a[i]-P[r])<=0)r--; P[++r]=a[i]; } h=r; for(int i=n-1;i>=1;i--) { if(a[i]==a[i+1])continue; while(h<r&&(P[r]-P[r-1])*(a[i]-P[r])<=0)r--; P[++r]=a[i]; } n=r-1;}void rc(){ int ans=dist(P[1],P[2]); for(int i=1,j=2;i<=n;i++) { int k=i%n+1; while(abs((P[i]-P[j])*(P[k]-P[j]))<abs((P[i]-P[j%n+1])*(P[k]-P[j%n+1])))j=j%n+1; ans=max(ans,max(dist(P[i],P[j]),dist(P[j],P[k]))); } printf("%d\n",ans);}int main(){ init(); graham(); rc(); return 0;}
第二题POJ3608
本题求的是两个不相交凸包的最近距离。
先保证两个凸包定点逆时针。设j为凸包A纵坐标最小的点,k为凸包B纵坐标最大的点。
首先逆时针枚举凸包A上的每条边(通过移动指针j,即使得直线与当前枚举的边重合),同时移动指针k(即维护两条直线平行,通过叉积算面积来判断),直至指针L转了一圈。然后再反过来枚举凸包B上的每条边(移动指针R),适当地移动指针L,再转一圈。
然后在求距离的时候要分情况
一种是求点到线段的最近距离,另一种是求线段和线段的最近距离。而第二种情况可以转化为四个点到线段的最近距离。
点到线段的最近距离我是用距离判投影再用面积法做的。
本题在poj用g++提交63ms,rank3。
#include <iostream>#include <cstring>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cmath>#include <list>#include <string>using namespace std;const int maxn=10003;const double eps=1e-10;int get(){ int f=0,v=0;char ch; while(!isdigit(ch=getchar()))if(ch=='-')break; if(ch=='-')f=1;else v=ch-48; while(isdigit(ch=getchar()))v=v*10+ch-48; if(f==1)return -v;else return v;}double getd(){ double d=0,d2=0,d3=1; char ch; bool flag=0; while(!isdigit(ch=getchar()))if(ch=='-')break; if(ch=='-')flag=true;else d=ch-48;while(isdigit(ch=getchar()))d=d*10+ch-48; if(ch=='.') { while(isdigit(ch=getchar()))d2=d2*10+ch-48,d3=d3*0.1; d+=d3*d2; } if(flag)return -d;else return d;}int sig(double x){ if(fabs(x)<=eps)return 0; return x>eps?1:-1;}struct Tpoint{ double x,y; Tpoint(){} Tpoint(double _x,double _y){x=_x,y=_y;} void getpoint(){x=getd(),y=getd();}}a[maxn],b[maxn];int n,m;double ans;double dist(Tpoint a){return sqrt(a.x*a.x+a.y*a.y);}Tpoint operator -(Tpoint a,Tpoint b){return Tpoint(a.x-b.x,a.y-b.y);}double operator *(Tpoint a,Tpoint b){return a.x*b.y-a.y*b.x;}void make(Tpoint a[maxn],int n){ for(int i=2;i<n;i++) { int tp=sig((a[i]-a[i-1])*(a[i+1]-a[i])); if(tp==0)continue; if(tp<0)reverse(a+1,a+1+n); return; }}double dist_pointseg(Tpoint p,Tpoint a,Tpoint b){ double PA=dist(p-a),PB=dist(p-b),AB=dist(a-b); if(min(PA*PA,PB*PB)+AB*AB<max(PA*PA,PB*PB))return min(PA,PB); else return fabs((a-p)*(b-p))/AB;}double mindist_segseg(Tpoint a,Tpoint b,Tpoint v,Tpoint u){ return min(min(dist_pointseg(a,u,v),dist_pointseg(b,u,v)),min(dist_pointseg(u,a,b),dist_pointseg(v,a,b)));}void rc(Tpoint a[maxn],int n,Tpoint b[maxn],int m){ int j=1,k=1; double tp; for(int i=2;i<=n;i++)if(a[i].y<a[j].y)j=i; for(int i=2;i<=m;i++)if(b[i].y>b[k].y)k=i; for(int i=1;i<=n;i++,j=j%n+1) { while(tp=(b[k]-a[j+1])*(a[j]-a[j+1])-(b[k+1]-a[j+1])*(a[j]-a[j+1])<eps)k=k%m+1; if(sig(tp)>0)ans=min(ans,dist_pointseg(b[k],a[j],a[j+1])); else ans=min(ans,mindist_segseg(a[j],a[j+1],b[k],b[k+1])); }}int main(){ while(n=get(),m=get(),n!=0) { for(int i=1;i<=n;i++)a[i].getpoint(); for(int i=1;i<=m;i++)b[i].getpoint(); make(a,n),make(b,m); a[n+1]=a[1],b[m+1]=b[1]; ans=1e10; rc(a,n,b,m),rc(b,m,a,n); printf("%.6f\n",ans); } return 0;}
- 旋转卡壳小结
- 旋转卡壳
- 旋转卡壳
- 旋转卡壳
- 旋转卡壳
- 旋转卡壳
- 旋转卡壳
- 旋转卡壳
- 旋转卡壳卡卡
- 旋转卡壳--Rotating Calipers
- 旋转卡壳算法
- 旋转卡壳算法
- Triangle 两次旋转卡壳
- 旋转卡壳模版代码
- poj 3608 (旋转卡壳)
- 旋转卡壳算法
- 旋转卡壳模板
- 旋转卡壳初步
- Storm基本概念
- SQLPutData()—Send Data in Segments
- 寒假必看
- 浅谈生成函数和多项式
- 单例
- 旋转卡壳小结
- Java_TCPIP_Socket编程(doc)下载
- 他隐藏的最深!!白夜行中的秋吉雄一!!!
- 转自沈乐杨的新浪博客----秋吉雄一
- 19. Notes客户机中的校验
- office 2010 安装出错
- javascript 实例:评分系统
- 找出数组中唯一出现一次的数
- 求二叉树的镜像