POJ1696 Space Ant(贪心、向量叉乘、向量极角、线段相交、点在线段上)

题目链接:

  http://poj.org/problem?id=1696

题目描述:

Space Ant

Description

The most exciting space discovery occurred at the end of the 20th century. In 1999, scientists traced down an ant-like creature in the planet Y1999 and called it M11. It has only one eye on the left side of its head and just three feet all on the right side of its body and suffers from three walking limitations:

  1. It can not turn right due to its special body structure.
  2. It leaves a red path while walking.
  3. It hates to pass over a previously red colored path, and never does that.

The pictures transmitted by the Discovery space ship depicts that plants in the Y1999 grow in special points on the planet. Analysis of several thousands of the pictures have resulted in discovering a magic coordinate system governing the grow points of the plants. In this coordinate system with x and y axes, no two plants share the same x or y
An M11 needs to eat exactly one plant in each day to stay alive. When it eats one plant, it remains there for the rest of the day with no move. Next day, it looks for another plant to go there and eat it. If it can not reach any other plant it dies by the end of the day. Notice that it can reach a plant in any distance. 
The problem is to find a path for an M11 to let it live longest. 
Input is a set of (x, y) coordinates of plants. Suppose A with the coordinates (xA, yA) is the plant with the least y-coordinate. M11 starts from point (0,yA) heading towards plant A. Notice that the solution path should not cross itself and all of the turns should be counter-clockwise. Also note that the solution may visit more than two plants located on a same straight line. 

Input

The first line of the input is M, the number of test cases to be solved (1 <= M <= 10). For each test case, the first line is N, the number of plants in that test case (1 <= N <= 50), followed by N lines for each plant data. Each plant data consists of three integers: the first number is the unique plant index (1..N), followed by two positive integers x and y representing the coordinates of the plant. Plants are sorted by the increasing order on their indices in the input file. Suppose that the values of coordinates are at most 100.

Output

Output should have one separate line for the solution of each test case. A solution is the number of plants on the solution path, followed by the indices of visiting plants in the path in the order of their visits.

Sample Input

2
10
1 4 5
2 9 8
3 5 9
4 1 7
5 3 2
6 6 3
7 10 10
8 8 1
9 2 4
10 7 6
14
1 6 11
2 11 9
3 8 7
4 12 8
5 9 20
6 3 2
7 1 6
8 2 13
9 15 1
10 14 17
11 13 19
12 5 18
13 7 3
14 10 16

Sample Output

10 8 7 3 4 9 5 6 2 1 10
14 9 10 11 5 12 8 7 6 13 4 14 1 3 2

题目大意:

  一只生物吃东西……它不能右转,走路会留下痕迹,且不能穿过之前走过的痕迹

  现在有这么多食物,要从y轴上与你第一个到达的点的投影出发,问最多可以吃几个食物

思路:

  想象生物面朝的方向延伸出一条射线,射线顺时针方向的所有区域和路径的相交为你剩下可以吃到的区域(搜索区域)

  所以每次转向都在缩小你的搜索区域,转得角度越大,缩小得越厉害

  贪心的思想,每次选择剩下可以走的点(注意判断之前线段都不想交)中,转角最小的那个点,这样会保证搜索区域尽可能的大

  起始点选择最下面的点,因为假设选择不是最下面的点,总存在点(起始点之下)永远不在你的搜索区域中

代码:

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <algorithm>
 4 #include <cstring>
 5 #include <cmath>
 6 using namespace std;
 7
 8 const double EPS = 1e-10;    //精度系数
 9 const int INF = 0x3f3f3f3f;
10 const double PI = acos(-1.0);
11 const int N = 55;
12
13 struct Point {
14     double x, y;
15     Point(double x = 0, double y = 0) :x(x), y(y) {}
16 };    //点的定义
17
18 typedef Point Vector;    //向量的定义
19
20 Vector operator - (Vector A, Vector B) { return Vector(A.x - B.x, A.y - B.y); }    //向量减法
21
22 int dcmp(double x) {
23     if (fabs(x) < EPS)return 0; else return x < 0 ? -1 : 1;
24 }    //与0的关系
25
26 double Cross(Vector A, Vector B) { return A.x*B.y - A.y*B.x; }    //向量叉乘
27 double Dot(Vector A, Vector B) { return A.x*B.x + A.y*B.y; }    //向量点乘
28 double Length(Vector A) { return sqrt(Dot(A, A)); }    //向量长度
29
30 double Angle(Vector A, Vector B) {
31     double ans = atan2(A.y, A.x) - atan2(B.y, B.x);
32     return ans + (ans < 0 ? 2 * PI : 0);
33 }    //向量夹角( 范围[0, 2π) )
34
35 bool SegmentProperIntersection(Point& a1, Point& a2, Point& b1, Point& b2) {
36     double c1 = Cross(a2 - a1, b1 - a1), c2 = Cross(a2 - a1, b2 - a1),
37         c3 = Cross(b2 - b1, a1 - b1), c4 = Cross(b2 - b1, a2 - b1);
38     return dcmp(c1)*dcmp(c2) < 0 && dcmp(c3)*dcmp(c4) < 0;
39 }    //判断两线段相交(恰有一个公共点且不在端点)
40
41 bool OnSegment(Point& p, Point& a1, Point& a2) {
42     return dcmp(Cross(a1 - p, a2 - p)) == 0 && dcmp(Dot(a1 - p, a2 - p)) < 0;
43 }    //判断点是否在一条线段上(不含端点)
44
45 int n, index[N], best, ans[N], res[N];
46 Point P[N];
47 bool vis[N];
48
49 bool ok(int cur, int next, int now) {
50     Point last(0, P[res[0]].y);
51     for (int i = 0; i < cur; ++i) {
52         if (SegmentProperIntersection(last, P[res[i]], P[now], P[next])
53             || OnSegment(P[res[i]], P[now], P[next]))return false;
54         last = P[res[i]];
55     }
56     return true;
57 }
58
59 void solve(int cur, int id, Vector v) {
60     double MIN = INF, L = INF;
61     int next = 0;
62     for (int i = 1; i <= n; ++i)if (!vis[i]) {    //如果没有访问过
63         double agl = Angle(P[i] - P[id], v);    //夹角
64         if (agl >= PI || !ok(cur, i, id))continue;    //保证方向,且与之前线段不相交
65         if (agl < MIN || (dcmp(agl - MIN) == 0 && Length(P[i] - P[id]) < L))    //扫描夹角最小的
66             MIN = agl, next = i, L = Length(P[i] - P[id]);
67     }
68     if (next) {
69         vis[next] = true;
70         res[cur] = next;
71         solve(cur + 1, next, P[next] - P[id]);
72         vis[next] = false;
73     } else if (cur > best) {    //不能再继续
74         best = cur;
75         memcpy(ans, res, sizeof(ans));
76     }
77 }
78
79 int main() {
80     int t;
81     cin >> t;
82     while (t--) {
83         memset(vis, 0, sizeof(vis));
84         best = 0;
85         cin >> n;
86         double tmp = INF;
87         int m;
88         for (int i = 1; i <= n; ++i) {
89             scanf("%d%lf%lf", &index[i], &P[i].x, &P[i].y);
90             if (P[i].y < tmp) { tmp = P[i].y, m = i; }    //找到y坐标最小的点
91         }
92         vis[m] = true;
93         res[0] = m;
94         solve(1, m, Vector(P[m].x, 0));
95         printf("%d", best);
96         for (int i = 0; i < best; ++i)printf(" %d", index[ans[i]]);
97         printf("\n");
98     }
99 }
时间: 2024-10-13 17:01:28

POJ1696 Space Ant(贪心、向量叉乘、向量极角、线段相交、点在线段上)的相关文章

poj1696 Space Ant

地址: 题目: Space Ant Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 4295   Accepted: 2697 Description The most exciting space discovery occurred at the end of the 20th century. In 1999, scientists traced down an ant-like creature in the pl

poj1696 Space Ant 2012-01-11

http://poj.org/problem?id=1696 __________________________________ 类似求凸包.满足一定可以经过所有点. __________________________________ 1 Program stone; 2 type coord=record 3 x,y,num:longint; 4 end; 5 var i,j,m,n,ax,le,heap:longint; 6 a:array[0..500]of coord; 7 f:ar

!HDU 4380 三角屋内有奇数个宝藏的三角形有多少个-计算几何-(向量叉乘&amp;线段与点的关系&amp;暴力枚举)

题意:小明要买三座房子,这三个房子构成一个三角形,已知n个房子的坐标,任何三个房子都不在一条直线上,又已知有m个宝藏的坐标,问房子构成的三角形内有奇数个宝藏的三角形有多少个.数据范围:n(3~100),m(1~1000) 分析: 简单的计算几何.记住这题的做法. 三角形内的点的个数=上面的线段下面的点的个数 -- 下面两条线段下面的点的个数(或者下面一条线段减上面两条线段,看具体位置情况,所以直接取绝对值就好) n个点有n(n-1)/2条线段,不超过1W,枚举每条线段,再枚举每个宝藏的坐标(10

向量叉乘求多变形面积

#include <iostream> #include <algorithm> #include <vector> #include <fstream> #include <cmath> using namespace std; struct Point { double x, y; }; //计算叉乘,平面上的点,所以向量总是沿z轴方向 double cross(const Point &A, const Point &B,

向量叉乘与叉乘矩阵

本文以三维向量来说明向量的叉乘计算原理以及叉乘矩阵如何求取 1.向量叉乘的计算原理              a.b分别为三维向量:                                                                                    a叉乘b一般定义为:                                      或              可是这只是一个符号的定义啊,具体怎么得到代数值呢             

【390】向量叉乘,判断向量位置

参考:二维向量叉乘公式 a×b = (x1y2-x2y1) 参考:叉积(点线)判断法 (P叉乘Q)P^Q>0说明P在Q的顺时针方向,<0说明P在Q的逆时针方向,=0说明P和Q共线. 可以用来判断一个多边形是否为凸多边形. 原文地址:https://www.cnblogs.com/alex-bn-lee/p/10688955.html

POJ 1696 Space Ant(点积的应用)

Space Ant 大意:有一只蚂蚁,每次都只向当前方向的左边走,问蚂蚁走遍所有的点的顺序输出.开始的点是纵坐标最小的那个点,开始的方向是开始点的x轴正方向. 思路:从开始点开始,每次找剩下的点中与当前方向所形成的夹角最小的点,为下一个要走的点(好像就是犄角排序,我不是很会),夹角就是用点积除以两个向量的距离,求一下acos值. 之前一直用叉积做,做了好久样例都没过,发现用错了... 题目挺好的,有助于理解点积与叉积 1 struct Point{ 2 double x, y; 3 int id

poj 1696 Space Ant(极角排序)

Space Ant Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 3661   Accepted: 2281 Description The most exciting space discovery occurred at the end of the 20th century. In 1999, scientists traced down an ant-like creature in the planet Y19

poj 1696 Space Ant(模拟+叉积)

Space Ant Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 3840   Accepted: 2397 Description The most exciting space discovery occurred at the end of the 20th century. In 1999, scientists traced down an ant-like creature in the planet Y19