poj 1696 :Space Ant (极角排序)

    xiaoxiao2021-04-13  32

    题意:一张图上给出n个点的坐标(xi,yi),其中xi,yi均为正整数。记这n个点中,拥有最小y的点为A,你开始从点(0, yA)开始走向点A,然后,你可以随意选择径直走去另外的点,但必须满足一下3个条件:

    1:只能向左转向。

    2:走过的路径为留下一条红色的轨迹。

    3:不能越过这条红色的轨迹。

    问你最多能到达几个点,并且按到达的顺序输出各个点的标号。

     

     

    思路:叉积的应用+dfs。易证:按照一定的顺序,每次选择当前左转角度最小的点(相等则选距离最近的点),必能按条件遍历所有的点。复习下叉积a * b的性质:

    1. 向量a到向量b成逆时针时,上述结果大于0; 2. 向量a到向量b成顺时针时,上述结果小于0;

    3. 向量a和向量b共线时(不论同向还是反向),上述结果等于0。

    #include<iostream> #include<cmath> #include<algorithm> using namespace std; const int Max = 52; const double eps = 1e-8; struct Point{ int id, order; double x, y; }p[Max]; int n; bool cmp(Point &a, Point &b){ return a.order < b.order; } double xmult(Point sp, Point ep, Point op){ return (sp.x-op.x)*(ep.y-op.y) - (ep.x-op.x)*(sp.y-op.y); } double mydis(Point p1, Point p2){ double a = p1.x - p2.x; double b = p1.y - p2.y; return sqrt(a*a + b*b); } void dfs(int pre, int dep){ if(dep == n) return; int i, mi = 0; while(p[mi].order != -1) mi ++; // 选择一个没有经过的点作为当前的最优解点。 for(i = mi + 1; i < n; i ++){ // 用另外的没有经过的点与当前最优解点比较,求出最优解的点。 if(p[i].order != -1) continue; double w = xmult(p[mi], p[i], p[pre]); if(w < -eps) mi = i; else if(abs(w) < eps && mydis(p[pre], p[i]) < mydis(p[pre], p[mi])) mi = i; } p[mi].order = dep; dfs(mi, dep + 1); } int main(){ int t, i, mi; cin >> t; while(t --){ cin >> n; for(mi = i = 0; i < n; i ++){ cin >> p[i].id >> p[i].x >> p[i].y; p[i].order = -1; if(p[i].y < p[mi].y) mi = i; } p[mi].order = 0; dfs(mi, 1); sort(p, p + n, cmp); // 按经过的顺序排列。 cout << n; for(i = 0; i < n; i ++) cout << ' ' << p[i].id; cout << endl; } return 0; }

    极角排序:

    分析:先找出最左下方的顶点(即纵坐标最小的顶点),然后对剩下的顶点按照对与左下点的极角排序,然后反复找最左下的点,反

    复进行极角排序,同时记录排序后左下的顶点.

    PS:如果给你一群凸包上的点,直接排序依次就好了

    #include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> using namespace std; const double eps = 1e-8; int sgn(double x) { if(fabs(x) < eps) return 0; if(x < 0) return -1; else return 1; } struct Point { double x, y; int index; Point(){} Point(double xx, double yy) : x(xx), y(yy){} Point operator - (const Point &a) const { return Point(x - a.x, y - a.y); } double operator ^ (const Point &a) const { return x*a.y - y*a.x; } double operator *(const Point &a) const { return x*a.x + y*a.y; } }; double dist(Point a, Point b) { return sqrt((a-b)*(a-b)); } int pos; Point p[105]; bool cmp(Point a, Point b) { double temp = (a-p[pos])^(b-p[pos]); if(sgn(temp) == 0) return dist(p[pos], a) < dist(p[pos], b); else if(sgn(temp) < 0) return false; else return true; } int main() { int t; scanf("%d", &t); int n; while(t--) { scanf("%d", &n); double x, y; for(int i = 0; i < n; i++) { scanf("%d%lf%lf", &p[i].index, &p[i].x, &p[i].y); if(p[i].y < p[0].y || (p[i].y == p[0].y && p[i].x < p[0].x)) swap(p[0], p[i]); } pos = 0; for(int i = 1; i < n; i++) { sort(p+i, p+n, cmp); pos++; } printf("%d ", n); for(int i = 0; i < n; i++) printf("%d%c",p[i].index, i == n-1 ? '\n' : ' '); } return 0; }

    转载请注明原文地址: https://ju.6miu.com/read-668537.html

    最新回复(0)