zoj 1249 极角排序

寻找蚂蚁路径算法
本文介绍了一种算法,用于解决平面中多个点上一只只能向左转的蚂蚁如何行走才能覆盖最多的点的问题。通过找到最左下方的点并按极角排序其他点来确定路径,确保路径不交叉且每点只被经过一次。

一只蚂蚁,只会向左转,现在给出平面上很多个点,求解一种走法,能使得蚂蚁能经过的点最多,每个顶点该蚂蚁只能经过一次,且所行走的路线不能发生交叉.

    对于题目所输入的点,先找出最左下方的顶点(即纵坐标最小的顶点),然后对剩下的顶点按照对与左下点的极角排序,然后反复找最左下的点,反复进行极角排序,同时记录排序后左下的顶点.
    极角排序方法:利用叉积,看向量p1和p2的叉积是否小于零,是则说明p1在p2逆时针方向,即p1的极角比p2的大,极角相同则按离p0距离降序排序.


const double eps = 1e-8 ;

double  add(double x , double y){
        if(fabs(x+y) < eps*(fabs(x) + fabs(y))) return 0 ;
        return x + y ;
}

struct  Point{
        double x , y ;
        int id ;
        Point(){}
        Point(double _x , double _y):x(_x),y(_y){}
        Point operator + (Point o){
              return Point(add(x , o.x) , add(y , o.y)) ;
        }
        Point operator - (Point o){
              return Point(add(x , -o.x) , add(y , -o.y)) ;
        }
        Point operator * (double o){
              return Point(x*o , y*o) ;
        }
        double operator ^(Point o){
               return add(x*o.y , -y*o.x) ;
        }
        double dist(Point o){
               return sqrt((x-o.x)*(x-o.x) + (y-o.y)*(y-o.y)) ;
        }
        void  read(){
              scanf("%d" , &id) ;
              scanf("%lf%lf" ,&x , &y) ;
        }
};

Point  po[108] ;
Point ox ;

bool cmp(Point a , Point b){
     double t = (a - ox) ^ (b - ox) ;
     if(t < 0) return 0 ;
     if(t > 0) return 1 ;
     return a.dist(ox) < b.dist(ox) ;
}

int  main(){
     int t  , k  , n , i  , j  , T = 1 ;
     vector<int> lis;
     cin>>t ;
     while(t--){
          cin>>n ;
          for(i = 0 ; i < n ; i++){
              po[i].read() ;
              if(po[0].y > po[i].y) swap(po[0] , po[i]) ;
          }
          lis.clear() ;
          ox = po[0] ;
          lis.push_back(ox.id) ;
          for(i = 1 ; i < n ; i++){
              sort(po+i , po+n , cmp) ;
              ox = po[i] ;
              lis.push_back(ox.id) ;
          }
          printf("%d" , lis.size()) ;
          for(i = 0 ; i < lis.size() ; i++) printf(" %d" ,lis[i]) ;
          puts("") ;
     }
     return 0 ;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值