POJ 3608 Bridge Across Islands(凸包最近对踵点对)

题目链接:http://poj.org/problem?id=3608

题意:求两个多边形的最近对踵点对。(已知两个多边形不相交)

思路:模板。

View Code 

 #include <iostream>

 #include <cstdio>

 #include <cmath>

 #include <algorithm>

 #define min(x,y) ((x)<(y)?(x):(y))

 using namespace std;

 

 

 struct point

 {

     double x,y;

 

     point(){}

     point(double _x,double _y)

     {

         x=_x;

         y=_y;

     }

 

 

     void get()

     {

         scanf("%lf%lf",&x,&y);

     }

 };

 

 const double EPS=1e-8;

 const int MAX=10005;

 point p[MAX],q[MAX],p1[MAX],q1[MAX],temp;

 int n,m,N,M;

 

 

 int DB(double x)

 {

     if(x>EPS) return 1;

     if(x<-EPS) return -1;

     return 0;

 }

 

 

 

 double Dis(point a,point b)

 {

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

 }

 

 //判断p在向量ab的哪一侧

 //右侧:返回正值

 //左侧:返回负值

 //在向量ab上返回0

 double cross(point a,point b,point p)

 {

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

 }

 

 

 int cmp(point a,point b)

 {

     double x=Dis(a,temp),y=Dis(b,temp);

     int flag=DB(cross(temp,a,b));

     if(flag) return flag==1;

     return DB(x-y)<=0;

 }

 

 void Graham(point p[],int n,point q[],int &m)

 {

     point t;

     int i,k=0,a,b;

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

     {

         a=DB(p[i].y-p[k].y);

         b=DB(p[i].x-p[k].x);

         if(a==-1||!a&&b==-1) k=i;

     }

     if(k!=0) t=p[0],p[0]=p[k],p[k]=t;

     temp=p[0];

     sort(p+1,p+n,cmp);

     q[0]=p[0];

     q[1]=p[1];

     p[n]=p[0];

     m=2;

     for(i=2;i<=n;i++)

     {

         while(m>1&&DB(cross(q[m-2],q[m-1],p[i]))<=0) m--;

         q[m++]=p[i];

     }

     m--;

 }

 

 

 

 

 

 double getAngle(point a1,point a2,point b1,point b2)

 {

     point t;

     t.x=b2.x-b1.x+a1.x;

     t.y=b2.y-b1.y+a1.y;

     return cross(a1,a2,t);

 }

 

 double Dis1(point a,point p,point q)

 {

     double t1=(q.x-p.x)*(a.x-p.x)+(q.y-p.y)*(a.y-p.y);

     double t2=(p.x-q.x)*(a.x-q.x)+(p.y-q.y)*(a.y-q.y);

     if(DB(t1)!=-1&&DB(t2)!=-1) return fabs(cross(a,p,q))/Dis(p,q);

     return min(Dis(a,p),Dis(a,q));

 }

 

 

 //凸包最近对踵点

 double calMinDis(point p[],int n,point q[],int m)

 {

     int sp=0,sq=0,i,a,b,tp,tq;

     double ans,flag;

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

     {

         a=DB(p[i].y-p[sp].y);

         b=DB(p[i].x-p[sp].x);

         if(a==-1||!a&&b==-1) sp=i;

     }

     for(i=0;i<m;i++)

     {

         a=DB(q[i].y-q[sq].y);

         b=DB(q[i].x-q[sq].x);

         if(a==1||!a&&b==1) sq=i;

     }

     ans=Dis(p[sp],q[sq]);

     tp=sp;

     tq=sq;

     do

     {

         flag=DB(getAngle(p[sp],p[(sp+1)%n],q[sq],q[(sq+1)%m]));

         if(flag==0)

         {

             ans=min(ans,Dis1(p[sp],q[sq],q[(sq+1)%m]));

             ans=min(ans,Dis1(p[(sp+1)%n],q[sq],q[(sq+1)%m]));

             ans=min(ans,Dis1(q[sq],p[sp],p[(sp+1)%n]));

             ans=min(ans,Dis1(q[(sq+1)%m],p[sp],p[(sp+1)%n]));

             sp=(sp+1)%n;

             sq=(sq+1)%m;

         }

         else if(flag==-1)

         {

             ans=min(ans,Dis1(q[sq],p[sp],p[(sp+1)%n]));

             sp=(sp+1)%n;

         }

         else

         {

             ans=min(ans,Dis1(p[sp],q[sq],q[(sq+1)%m]));

             sq=(sq+1)%m;

         }

     }while(tp!=sp||tq!=sq);

     return ans;

 }

 

 

 int main()

 {

     while(scanf("%d%d",&n,&m),n||m)

     {

         int i;

         for(i=0;i<n;i++) p[i].get();

         for(i=0;i<m;i++) q[i].get();

         Graham(p,n,p1,N);

         Graham(q,m,q1,M);

         double ans=calMinDis(p1,N,q1,M);

         printf("%.5lf\n",ans);

     }

     return 0;

 }

  

 

你可能感兴趣的:(bridge)