POJ 3608 Bridge Across Islands(两个凸包最近距离,旋转卡壳)(一)

2014-11-24 10:52:21 · 作者: · 浏览: 2

题目:两个不相交的多边形,求最近距离。
http://poj.org/problem id=3608
这里有详细的讲解:http://cgm.cs.mcgill.ca/~orm/mind2p.html
这是找到第一个凸包的左下角点,找到第二个凸的右下角的点,两条平行线卡壳。
然后开始旋转,分为三种情况:
两条线和两个凸包都重合,以及和其中一个凸包重合。
转变成线段与线段的最短距离,以及点与线段的最短距离,注意线段与线段的距离不等价于直线与直线的最短距离。
十分蛋疼的一题,估计很少有人1A,细节很多。
[cpp]
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define LL long long
#define eps 1e-8
#define inf 999999.0
#define zero(a) abs(a) #define N 20
#define pi acos(-1.0)
using namespace std;
struct Point{
double x,y;
}p[10005],q[10005],pos;
vectors1,s2;
double dist(Point p1,Point p2){
return sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y));
}
double xmul(Point p0,Point p1,Point p2){
return (p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y);
}
//Graham_scan求凸包
bool cmp(Point p1,Point p2){
if(xmul(pos,p1,p2)>eps) return true;
else if(zero(xmul(pos,p1,p2))&&dist(pos,p1) return false;
}
void Graham_scan(vector&s,Point p[],int n){
for(int i=1;i if(p[i].y swap(p[i],p[0]);
pos=p[0];
sort(p+1,p+n,cmp);
s.clear();
s.push_back(p[0]);s.push_back(p[1]);s.push_back(p[2]);
for(int i=3;i while(s.size()>=2&&xmul(s[s.size()-2],s[s.size()-1],p[i]) s.push_back(p[i]);
}
}

//得到向量a1b1和a2b2的位置关系
double Get_angle(Point a1,Point b1,Point a2,Point b2){
Point t;
t.x=a2.x-(b2.x-a1.x);
t.y=a2.y-(b2.y-a1.y);
return xmul(a1,b1,t);
}
double Dist_Point_Seg(Point p,Point a,Point b){
Point t=p;
t.x+=a.y-b.y;t.y+=b.x-a.x;
if(xmul(a,t,p)*xmul(b,t,p)>eps)
return dist(p,a)+eps else
return fabs(xmul(p,a,b))/dist(a,b);
}
double Min_Dist_Two_Polygons(vectors1,vectors2){
int na=s1.size(),nb=s2.size();
int lp=0,lq=0;
for(int i=1;i if(s1[i].y lp=i;
for(int i=1;i if(s2[i].y>s2[lq].y||(zero(s2[i].y-s2[lq].y)&&s2[i].x>s2[lq].x))
lq=i;
s1.push_back(s1[0]);s2.push_back(s2[0]);
double ans=dist(s1[lp],s2[lq]);
int tp=lp,tq=lq;
do{
double angle=Get_angle(s1[tp],s1[tp+1],s2[tq],s2[tq+1]);
//和两个凸包的边都重合
if(zero(angle)){
ans=min(ans,Dist_Point_Seg(s1[tp],s2[tq],s2[tq+1]));
ans=min(ans,Dist_Point_Seg(s1[tp+1],s2[tq],s2[tq+1]));
ans=min(ans,Dist_Point_Seg(s2[tq],s1[tp],s1[tp+1]));
ans=min(ans,Dist_Point_Seg(s2[tq+1],s1[tp],s1[tp+1]));
tp=(tp+1)%na;tq=(tq+1)%nb;
}
else{
//和第二个凸包的边重合
if(angle<-eps){
ans=min(ans,Dist_Point_Seg(s1[tp],s2[tq],s2[tq+1]));
tq=(tq+1)%nb;
}
//和第一个凸包的边重合
else{
ans=min(ans,Dist_Point_Seg(s2[tq],s1[tp],s1[tp+1]));
tp=(tp+1)%na;
}
}
}while(!(lp==tp&&lq==tq));
return ans;
}
int main(){
int n,m;
while(scanf("%d%d",&n,&m)!=EOF&&n+m){
for(int i=0;i scanf("%lf%lf",&p[i].x,&p[i].y);
Graham_scan(s1,p,n);
for(int i=0;i scanf("%lf%lf",&q[i].x,&q[i].y);
Graham_scan(s2,q,m);
print