POJ3130排序增量法

这是POJ3130的一段AC代码,使用zzy的排序增量法解决。算法流程完全按照 http://blog.csdn.net/u012061345/article/details/23872929所述
#include <iostream>
#include <algorithm>
using namespace std;
 
double const EPS = 1E-6;
 
#define isZero(x) ( - EPS <= (x) && (x) <= EPS )
#define isEq(x,y) isZero( (x) - (y) )
 
struct point_t{
 int x;
 int y;
 point_t(int a=0,int b=0):x(a),y(b){}
};

struct point64f_t{
 double x;
 double y;
 point64f_t(double a=0.0,double b=0.0):x(a),y(b){}
};

struct hp_t{
 double a;
 double b;
 double c;//ax+by+c>=0,法向量始终是(a,b)
};

//根据法向量的极角排序(-180,180],极角相同,越靠近法向量的越小
bool operator < (hp_t const&l,hp_t const&r){
    //法向量分别位于x轴上下,可以直接得到结果
    int ly = l.b >= 0 ? 1 : -1;
    int ry = r.b >= 0 ? 1 : -1;
    if ( ly != ry ) return ly < ry;

    //如果都位于x轴上
    if ( isZero(l.b) && isZero(r.b) && l.a * r.a < 0 )
        return l.a > r.a;
    double chaji = l.a * r.b - l.b * r.a;
    if ( !isZero(chaji) ) return chaji > 0;
   
    //法向量完全平行,当a为正时
    if ( l.a > EPS ){
       //若hp1比hp2更靠近法向量,则必有a1x+b1y+c1=0而a2x+b2y+c2>0
       return l.c * r.a < l.a * r.c;
    }
    if ( l.a < - EPS )return l.c * r.a > l.a * r.c;
   
    //a如果为0,b必然不为0
    if ( l.b > EPS ) return l.c * r.b < l.b * r.c;
    return l.c * r.b > l.b * r.c;
}
//判断半平面是否平行
bool isPara(hp_t const&l,hp_t const&r){
    int ly = l.b >= 0 ? 1 : -1;
    int ry = r.b >= 0 ? 1 : -1;
    if ( ly != ry ) return false;
    if ( isZero(l.b) && isZero(r.b) ) return l.a * r.a > 0;
    return isZero( l.a * r.b - r.a * l.b );
}

//从l到r,保证是逆时针方向,a、b是唯一确定的
inline void genHP(point_t const&l,point_t const&r,hp_t&hp){
    hp.a = (double)( l.y - r.y );
    hp.b = (double)( r.x - l.x );
    hp.c = (double)( l.x * r.y - l.y * r.x );
}
//半平面相交求交点,保证有且只有一个交点
inline void inter(hp_t const&l,hp_t const&r,point64f_t&p){
    double xishu = l.a * r.b - r.a * l.b;
    p.x = ( l.b * r.c - r.b * l.c ) / xishu;
    p.y = ( l.c * r.a - l.a * r.c ) / xishu;
}

//判断点是否在半平面内
inline bool isIn(point64f_t const&p,hp_t const&hp){
    double v = hp.a * p.x + hp.b * p.y + hp.c;
    return v >= - EPS;
}

//排序增量法,会改变hp里面的内容
bool sandi(hp_t hp[],int n){
    int bot = 0;
    int top = 1;
   
    for(int i=2;i<n;++i){
        //最前端的两个半平面相交
        while( bot < top ){
           point64f_t p;
           inter(hp[top-1],hp[top],p);
           //p在当前半平面外,出队列
           if ( isIn(p,hp[i]) ) break;
          else                 --top;
       }
       //最底端的两个半平面相交
       while( bot < top ){
           point64f_t p;
           inter(hp[bot],hp[bot+1],p);
          //p在当前半平面外,出队列
          if ( isIn(p,hp[i]) ) break;
          else                 ++bot;
       }
    
       //赋值
        hp[++top] = hp[i];
   }

     //后处理
     while( bot < top ){
         point64f_t p;
         inter(hp[top-1],hp[top],p);
        //p在当前半平面外,出队列
        if ( isIn(p,hp[bot]) ) break;
       else                   --top;
    }
    while( bot < top ){
         point64f_t p;
         inter(hp[bot],hp[bot+1],p);
         //p在当前半平面外,出队列
        if ( isIn(p,hp[top]) ) break;
       else                   ++bot;
    }

   return top - bot > 1;
}
 
point_t P[55];
hp_t Hp[55];

int main(){
 int n;
 while( scanf("%d",&n) && n ){
  for(int i=0;i<n;++i)scanf("%d%d",&P[i].x,&P[i].y);
  P[n] = P[0];
  //生成半平面
        for(int i=0;i<n;++i) genHP(P[i],P[i+1],Hp[i]);
  //排序
        sort(Hp,Hp+n);
  //完全平行的半平面只取一个
  hp_t* p = unique(Hp,Hp+n,isPara);
  //待处理的半平面个数 
  n = p - Hp;
  //S&I
  printf(sandi(Hp,n)?"1\n":"0\n");
 }
 return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值