poj2187-旋转卡壳

题目链接:http://poj.org/problem?id=2187

Description
Bessie, Farmer John’s prize cow, has just won first place in a bovine beauty contest, earning the title ‘Miss Cow World’. As a result, Bessie will make a tour of N (2 <= N <= 50,000) farms around the world in order to spread goodwill between farmers and their cows. For simplicity, the world will be represented as a two-dimensional plane, where each farm is located at a pair of integer coordinates (x,y), each having a value in the range -10,000 … 10,000. No two farms share the same pair of coordinates.
Even though Bessie travels directly in a straight line between pairs of farms, the distance between some farms can be quite large, so she wants to bring a suitcase full of hay with her so she has enough food to eat on each leg of her journey. Since Bessie refills her suitcase at every farm she visits, she wants to determine the maximum possible distance she might need to travel so she knows the size of suitcase she must bring.Help Bessie by computing the maximum distance among all pairs of farms.

Input

  • Line 1: A single integer, N
  • Lines 2..N+1: Two space-separated integers x and y specifying coordinate of each farm

Output

  • Line 1: A single integer that is the squared distance between the pair of farms that are farthest apart from each other.

Sample Input
4
0 0
0 1
1 1
1 0

Sample Output
2

Hint
Farm 1 (0, 0) and farm 3 (1, 1) have the longest distance (square root of 2)

题意
求所给点中任意两点的最长距离。

思路
n2肯定是过不了的…此处先用所给点建成多边形然后,用旋转卡壳的方式求多边形的直径,直径即为多边形上距离最远的两个点。


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
#include 
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const double eps = 1e-8;
const double pi = acos(-1.0);
const int maxn = 52100;
using namespace std;
int sgn(double x) {
if (fabs(x) < eps) return 0;
if (x < 0) return -1;
else return 1;
}
struct Point {
double x, y;
Point() {}
Point(double _x, double _y) { x = _x; y = _y; }//初始化
void input() {//输入
scanf("%lf%lf", &x, &y);
}
void output() {
printf("%.2f %.2f\n", x, y);
}
bool operator == (Point b) const { return sgn(x - b.x) == 0 && sgn(y - b.y) == 0; }
bool operator < (Point b) const { return sgn(x - b.x) == 0 ? sgn(y - b.y) < 0 : x < b.x; }//x相等输出y较小的
Point operator - (const Point &b) const { return Point(x - b.x, y - b.y); }
double operator ^ (const Point &b) const { return x * b.y - y * b.x; }//向量叉积
double operator * (const Point &b) const { return x * b.x + y * b.y; }//向量点积
Point operator * (const double &k) const { return Point(x*k, y*k); }
Point operator / (const double &k) const { return Point(x / k, y / k); }
Point operator + (const Point &b) const { return Point(x + b.x, y + b.y); }
double len() { return hypot(x, y); }//向量长度
double len2() { return x * x + y * y; }//长度平方
int Dist(Point p) { return (x-p.x)*(x-p.x)+(y-p.y)*(y-p.y); }//两点距离
};
double xmult(Point p, Point a, Point b) { return((a - p) ^ (b - p)); }//向量pa与pb的叉积
double dmult(Point p, Point a, Point b) { return((a - p)*(b - p)); }//向量pa与pb的点积
struct Line {//无向直线or线段
Point s, e;
Line() {}
Line(Point _s, Point _e) { s = _s; e = _e; }
Line(double a, double b, double c) {//直线ax+by+c=0
if (sgn(a) == 0) {
s = Point(0, -c / b);
e = Point(1, -c / b);
}
else if (sgn(b) == 0) {
s = Point(-c / a, 0);
e = Point(-c / a, 1);
}
else {
s = Point(0, -c / b);
e = Point(1, (-c - a) / b);
}
}
void input() {
s.input();
e.input();
}
double length() {//线段长度
return s.Dist(e);
}
bool parallel(Line v) {//判断两直线or两线段是否平行
return sgn((e - s) ^ (v.e - v.s)) == 0;
}
double dispointtoline(Point p) {//点p到直线的最短距离(平行四边形面积除以底)
return fabs(xmult(s, e, p)) / length();
}
Point lineprog(Point p) {//点p到直线最短距离的交点
return s + (((e - s)*((e - s)*(p - s))) / (e - s).len2());
}
Point crosspoint(Line v) {
double a1 = (v.e - v.s) ^ (s - v.s);
double a2 = (v.e - v.s) ^ (e - v.s);
return Point((s.x*a2 - e.x*a1) / (a2 - a1), (s.y*a2 - e.y*a1) / (a2 - a1));
}
bool pointonseg(Point p) {//点p是否在线段上
return sgn((p - s) ^ (e - s)) == 0 && sgn((p - s)*(p - e)) <= 0;
}
bool SegmentProperIntrrsection(Line b) {//线段a与b是否规范相交
int c1 = sgn(xmult(s, e, b.s)), c2 = sgn(xmult(s, e, b.e));
int c3 = sgn(xmult(b.s, b.e, s)), c4 = sgn(xmult(b.s, b.e, e));
if ((c1*c2) < 0 && (c3*c4) < 0)
return 1;
return 0;
}
bool UnSegmentProperIntrrsection(Line b) {//判断线段a,b是否存在交点(非规范相交)
if (sgn(max(s.x, e.x) - min(b.s.x, b.e.x)) >= 0 && sgn(max(b.s.x, b.e.x) - min(s.x, e.x)) >= 0
&& sgn(max(s.y, e.y) - min(b.s.y, b.e.y)) >= 0 && sgn(max(b.s.y, b.e.y) - min(s.y, e.y)) >= 0
&& sgn(xmult(s, b.e, b.s))*sgn(xmult(e, b.e, b.s)) <= 0 && sgn(xmult(b.s, s, e))*sgn(xmult(b.e, s, e)) <= 0)
return 1;
return 0;
}
Point NearestPointToLineSeg(Point a) {//求点a到线段最近的点
Point ans;
double t = (a - e)*(s - e) / ((s - e)*(s - e));
if (t >= 0 && t <= 1) {
ans.x = e.x + (s.x - e.x)*t;
ans.y = e.y + (s.y - e.y)*t;
}
else {
if (a.Dist(e) > a.Dist(s))
ans = s;
else
ans = e;
}
return ans;
}
Point jiaodian(Line b) {//计算两线段交点坐标,前提:已确定两线段相交
Point ans = s;
double t = ((s - b.s) ^ (b.s - b.e)) / ((s - e) ^ (b.s - b.e));
ans.x += (e.x - s.x)*t;
ans.y += (e.y - s.y)*t;
return ans;
}
};

struct polygon {//多边形
int n;//顶点数
Point p[maxn];//顶点
Line l[maxn];//线段
void getline() {//通过顶点得到线段
for (int i = 0; i < n; i++)
l[i] = Line(p[i], p[(i + 1) % n]);
}
void input(int _n) {
n = _n;
for (int i = 0; i < n; i++)
p[i].input();
}
bool isconvex() {//判断多边形是否是凸多边形
bool vis[4];
memset(vis, 0, sizeof(vis));
for (int i = 0; i < n; i++) {
vis[sgn(xmult(p[i], p[(i + 1) % n], p[(i + 2) % n])) + 1] = 1;
if (vis[0] && vis[2])
return 0;
}
return 1;
}
int relationpoint(Point q) {//判断点与任意多边形的关系// 3 点上,2 边上,1 内部,0 外部
for (int i = 0; i < n; i++) {
if (p[i] == q)return 3;
}
getline();
for (int i = 0; i < n; i++) {
if (l[i].pointonseg(q))return 2;
}
int cnt = 0;
for (int i = 0; i < n; i++) {
int j = (i + 1) % n;
int k = sgn((q - p[j]) ^ (p[i] - p[j]));
int u = sgn(p[i].y - q.y);
int v = sgn(p[j].y - q.y);
if (k > 0 && u < 0 && v >= 0)cnt++;
if (k < 0 && v < 0 && u >= 0)cnt--;
}
return cnt != 0;
}
bool judge() {//判断多边形端点的顺序,顺时针返回0,逆时针返回1
double sum = 0;
for (int i = 1; i < n; i++) {
sum += xmult(p[0], p[i], p[(i + 1) % n]);
}
if (sum < 0)
return 1;
return 0;
}
polygon Graham() {//凸包
polygon ans;
int m = 0;
sort(p, p + n);//Point先排序x小的,然后y小的
for (int i = 0; i < n; i++) {
while (m > 1 && sgn(xmult(ans.p[m - 2], ans.p[m - 1], p[i]) <= 0))
m--;
ans.p[m++] = p[i];
}
int k = m;
for (int i = n - 2; i >= 0; i--) {
while (m > k && sgn(xmult(ans.p[m - 2], ans.p[m - 1], p[i]) <= 0))
m--;
ans.p[m++] = p[i];
}

if (n > 1)
m--;
ans.n = m;
return ans;
}
int Rotating() {//旋转卡壳计算凸包的最远点对
if (n == 1)
return 0;
if (n == 2)
return p[0].Dist(p[1]);
int j = 2;
int ans = 0;
for (int i = 0; i < n; i++) {
while (xmult(p[i], p[(i + 1) % n], p[j]) < xmult(p[i], p[(i + 1) % n], p[(j + 1) % n]))
j = (j + 1) % n;
ans = max(ans, max(p[i].Dist(p[j]), p[(i + 1) % n].Dist(p[j])));
}
return ans;
}
};

struct halfplane : public Line {//有向直线
double angle;//弧度
halfplane() {}
halfplane(Point _s, Point _e) {
s = _s; e = _e;
}
halfplane(Line v) {
s = v.s; e = v.e;
}
void output() {
printf("s: (%f,%f)\n", s.x, s.y);
printf("e: (%f,%f)\n", e.x, e.y);
}
void calcangle() {//得到极角
angle = atan2(e.y - s.y, e.x - s.x);
}
bool operator < (const halfplane &b)const {
return angle < b.angle;
}

};
struct halfplanes {//半平面交
int n;//半平面的数量
halfplane hp[maxn];//半平面
Point p[maxn];//半平面交的交点
int que[maxn];//双向队列
int f, l;
void push(halfplane tmp) {
hp[n++] = tmp;
}
//去重
void unique() {
int m = 1;
for (int i = 1; i < n; i++) {
if (sgn(hp[i].angle - hp[i - 1].angle) != 0)
hp[m++] = hp[i];
else if (sgn(xmult(hp[m - 1].s, hp[m - 1].e, hp[i].s)) > 0)
hp[m - 1] = hp[i];
}
n = m;
}
bool halfplaneinsert() {//半平面交主程序返回是否存在半平面交
for (int i = 0; i < n; ++i)
hp[i].calcangle();
sort(hp, hp + n);//按极角大小排序
unique();
que[f = 0] = 0;
que[l = 1] = 1;
p[1] = hp[0].crosspoint(hp[1]);
for (int i = 2; i < n; i++) {
while (f < l && sgn(xmult(hp[i].s, hp[i].e, p[l])) < 0)l--;
while (f < l && sgn(xmult(hp[i].s, hp[i].e, p[f + 1])) < 0)f++;
que[++l] = i;
if (hp[i].parallel(hp[que[l - 1]]))
return false;
p[l] = hp[i].crosspoint(hp[que[l - 1]]);
}
while (f < l && sgn(xmult(hp[que[f]].s, hp[que[f]].e, p[l])) < 0)l--;
while (f < l && sgn(xmult(hp[que[l]].s, hp[que[l]].e, p[f + 1])) < 0)f++;
if (f + 1 >= l)
return false;
return true;
}
//得到最后半平面交得到的凸多边形
//需要先调用 halfplaneinsert() 且返回 true
void getconvex(polygon &ans) {
p[f] = hp[que[f]].crosspoint(hp[que[l]]);
ans.n = l - f + 1;
for (int j = f, i = 0; j <= l; ++i, ++j)
ans.p[i] = p[j];
}
};
polygon P, ans;
int main() {
int n;
while (scanf("%d", &n) != EOF) {
P.input(n);
ans = P.Graham();
int ans1 = ans.Rotating();
printf("%d\n", ans1);
}

谢谢你请我吃糖果

你可能感兴趣的:(poj2187-旋转卡壳)