极角排序

Space Ant
题意:
一张图上给出n个点的坐标(xi,yi),其中xi,yi均为正整数。记这n个点中,拥有最小y的点为A,你开始从点(0, yA)开始走向点A,然后,你可以随意选择径直走去另外的点,但必须满足一下3个条件:
1:只能向左转向。
2:走过的路径为留下一条红色的轨迹。
3:不能越过这条红色的轨迹。
问你最多能到达几个点,并且按到达的顺序输出各个点的标号。
题解:
本题其实就是用极角排序,每次都有一个你的当前点,然后每次都贪心的走以当前点为中心的极角最小的那个点(如果有多个,就走距离当前点最近的那个点即可.)
这样,我们能保证能走过的点数是最多的.

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
const int MAXN=60;
const int INF=0x3f3f3f3f3f;
const double EPS=1e-10;
struct Point
{
    double x,y;
    int id;
    Point(double x=0,double y=0):x(x),y(y){}
};
Point p[MAXN],ans[MAXN];
int now;
typedef Point Vector;
Vector operator -(Vector A,Vector B)
{
    return Vector(A.x-B.x,A.y-B.y);
}
double cross(Vector A,Vector B)
{
    return A.x*B.y-A.y*B.x;
}
double distance(Vector A)
{
    return A.x*A.x+A.y*A.y;
}
bool cmp(const Point &a,const Point &b)
{
    double res=cross(a-p[now],b-p[now]);//选择离当前点最外层的点
    if(res>0) return true;
    else if(abs(res)<EPS&&distance(a-p[now])<distance(b-p[now])) return true;
    //如果三点共线,选择离当前点近的
    else return false;
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int n;
        scanf("%d",&n);
        for(int i=0;i<n;i++)
        {
            scanf("%d%lf%lf",&p[i].id,&p[i].x,&p[i].y);
            if(p[i].y<p[0].y) swap(p[0],p[i]);
        }
        now=0;
        sort(p+1,p+n,cmp);//以0为基准找到下一个基准点
        int idx=0;
        ans[idx++]=p[now++];//把0放进去
        for(int i=2;i<n;i++)
        {
            sort(p+i,p+n,cmp);//以now为基准,找到下一个基准点
            ans[idx++]=p[now++];//把now放进去
        }
        ans[idx++]=p[now++];
        printf("%d",idx);
        for(int i=0;i<idx;i++)
        {
            printf(" %d",ans[i].id);
        }
        printf("\n");
    }
    return 0;
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容