极角排序 POJ1696

来源:互联网 发布:里诺仓库管理软件sql 编辑:程序博客网 时间:2024/05/21 15:48

VJ题目连接

题目大意

一种奇怪的虫子不能右转且走过路线之间不能有交点,吃植物才能存活,给出植物的坐标,求虫子要怎样走才能活得最久(吃的植物越多活越久)

输入:样例数,n组样例,每组给出一个n,然后n行每行给出3个数,分别是植物编号、植物x坐标、植物y坐标

输出:能吃的最大植物数目,并给出路线

解体思路

因为虫子只能左转且路线不能有交点,很容易想到让虫子逆时针螺旋地去吃植物,由外到内,可以将所有植物吃完。因为逆时针路线一定是左转,螺旋线保证不相交,从最外到最内是肯定可以吃完所有植物的。

怎样构造这样的螺旋线呢?这要用极角排序。从最下方的点开始,将这个点作为基点,对其他所有点进行极角排序,然后取极角最小点,重新设立为基点,对剩余点重新排序,依次类推直至剩最后一个点。

为什么要从最下点开始?因为这样可以保证其他点都在上方,这样就可以使其他点与该点的极角都>=0,这样可以以x轴正方向为基线找出夹角最小的点。之后由找到的新点为基点,可以保证其他未选择的点都在上一个点与新基点连线的一侧,这样就可以以这条连线作为基线求最小极角。

怎样求对极角进行排序?简单的做法是用sort函数,然后自定义一个cmp比较函数,大致如下:

//极角排序规则 bool cmp(const Point &p1, const Point &p2)  {      double tmp;      tmp=multiply(p1,p2,PointSet[cnt]);      //外积大于0     if(tmp>0)    {          return true;      }      //两线重合时选择距离更小的     else if(fabs(tmp)<=eps && dis(PointSet[cnt],p1)<dis(PointSet[cnt],p2))    {          return true;      }      return false;  } 

这里没有直接求角度,而是利用外积来判断,外积函数如下:

//小于0,说明向量p0p1的极角大于p0p2的极角double multiply(Point p1,Point p2,Point p0){    return((p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y));}

显然,若p1p0与p2p0的外积>0,则p1在p2右侧(若以上述的基线为水平线),相反,若外积<0,则p1在p2左侧,而我们要的极角最小的点即在最右侧的点。若外积为0,则三点共线,我们需要优先选择更靠近基点的点。

AC代码

#include <iostream>#include <cmath>#include <cstdio>#include <cstring>#include <algorithm>#define eps 0.00000001using namespace std;struct Point{    double x,y,num;};const int maxN=55;Point PointSet[maxN];       //输入的点集 Point ans[maxN];            //输出的点集 int n;      //点的个数 int cnt;    //当前判断基点 //小于0,说明向量p0p1的极角大于p0p2的极角double multiply(Point p1,Point p2,Point p0){    return((p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y));}//p1p2距离 double dis(Point p1,Point p2){    return(sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y)));}//极角排序规则 bool cmp(const Point &p1, const Point &p2)  {      double tmp;      tmp=multiply(p1,p2,PointSet[cnt]);      //外积大于0     if(tmp>0)    {          return true;      }      //两线重合时选择距离更小的     else if(fabs(tmp)<=eps && dis(PointSet[cnt],p1)<dis(PointSet[cnt],p2))    {          return true;      }      return false;  } int main(){    int cas;    scanf("%d",&cas);    while(cas--)    {        scanf("%d",&n);        memset(PointSet,0,sizeof PointSet);        int i;        for(i=0;i<n;i++)        {            scanf("%d%lf%lf",&PointSet[i].num,&PointSet[i].x,&PointSet[i].y);            //找出最下点             if(PointSet[i].y<PointSet[0].y)            {                Point tmp=PointSet[0];                PointSet[0]=PointSet[i];                PointSet[i]=tmp;            }        }        //初始基点         cnt=0;        //排序         sort(PointSet+1,PointSet+n,cmp);        ans[cnt]=PointSet[cnt++];        for(i=2;i<n;i++)        {            //依次设立基点排序             sort(PointSet+cnt,PointSet+n,cmp);            ans[cnt]=PointSet[cnt++];        }        ans[cnt]=PointSet[cnt++];        printf("%d",cnt);        for(i=0;i<cnt;i++)        {            printf(" %d",ans[i].num);        }        printf("\n");    }    return 0;}
0 0
原创粉丝点击