题目大意
给出一个多边形A(保证边平行于坐标轴),要用另一个多边形B(边也必须平行于坐标轴)把A围起来,求:
1)B的最小周长;
2)B在满足1)的前提下的最小面积。
输入输出
输入A的边数N,和N个顶点的坐标(均为整数)。
输出1)和2)的答案,各占一行。
数据范围
4≤N≤100000,坐标的绝对值≤1e9
解析
1)对于第一问,可以把B等价为一个边平行于坐标轴的矩形,于是答案显而易见的等于(max_x – min_x + max_y – min_y) * 2;(然而我最开始SB地求了个凸包……)
2)对于第二问,为了满足B的边长最小,“凹进去”的边显然不可取,由于边平行于坐标轴,我们可以把点按x排序,上下两个单调栈维护y,需要注意的是只有当出现“凹”形的时候才能pop,也就是说实际上维护的是一个“峰”(大概不叫单调栈了):
还有就是y相等的点不能直接pop掉。
然后从左到右一段一段地算面积加入答案即可,具体见代码。
代码
求了凸包的版本:
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <iomanip> 5 #include <cmath> 6 #include <algorithm> 7 8 typedef long long LL; 9 const LL INF = 0x3f3f3f3f3f3f3f3f; 10 struct Point { 11 LL x, y; 12 Point(LL _x = 0, LL _y = 0):x(_x), y(_y) {}; 13 Point operator -(const Point &) const; 14 bool operator <(const Point &) const; 15 friend LL cross(const Point &, const Point &); 16 } point[100010]; 17 int N, convex[100010], tail; 18 19 void calculate_convex(); 20 LL calculate_perimeter(); 21 LL calculate_area(); 22 23 int main() { 24 #ifndef ONLINE_JUDGE 25 freopen("2146.in", "r", stdin); 26 freopen("2146.out", "w", stdout); 27 #endif 28 std::ios::sync_with_stdio(false); 29 std::cin >> N; 30 for (int i = 0; i < N; i++) 31 std::cin >> point[i].x >> point[i].y; 32 std::sort(point, point + N); 33 calculate_convex(); 34 std::cout << calculate_perimeter() << std::endl << calculate_area() << std::endl; 35 36 return 0; 37 } 38 Point Point::operator -(const Point &p) const { return Point(x - p.x, y - p.y); } 39 bool Point::operator <(const Point &p) const { return x == p.x ? y < p.y : x < p.x; } 40 LL cross(const Point &a, const Point &b) { return a.x * b.y - a.y * b.x; } 41 void calculate_convex() { 42 for (int i = 0; i < N; i++) { 43 while (tail > 1 && cross(point[convex[tail - 1]] - point[convex[tail - 2]], point[i] - point[convex[tail - 1]]) >= 0) 44 tail--; 45 convex[tail++] = i; 46 } 47 int size_up = tail - 1; 48 for (int i = N - 2; i >= 0; i--) { 49 while (tail - size_up > 1 && cross(point[convex[tail - 1]] - point[convex[tail - 2]], point[i] - point[convex[tail - 1]]) >= 0) 50 tail--; 51 convex[tail++] = i; 52 } 53 tail--; 54 } 55 LL calculate_perimeter() { 56 LL res = 0; 57 for (int i = 0; i < tail; i++) { 58 res += abs(point[convex[i]].x - point[convex[i + 1]].x); 59 res += abs(point[convex[i]].y - point[convex[i + 1]].y); 60 } 61 return res; 62 } 63 LL calculate_area() { 64 int stk1[100010], top1 = 0, stk2[100010], top2 = 0; 65 LL res = 0, maxy = -INF, miny = INF; 66 for (int i = 0; i < N; i++) { 67 while (top1 > 0 && point[i].y > point[stk1[top1 - 1]].y && maxy > point[stk1[top1 - 1]].y) 68 --top1; 69 stk1[top1++] = i; 70 maxy = std::max(maxy, point[i].y); 71 while (top2 > 0 && point[i].y < point[stk2[top2 - 1]].y && miny < point[stk2[top2 - 1]].y) 72 --top2; 73 stk2[top2++] = i; 74 miny = std::min(miny, point[i].y); 75 } 76 LL tmp1 = point[stk1[0]].y, tmp2 = point[stk2[0]].y; 77 for (int i = 0, j = 0, lastx = point[0].x; i < top1;) { 78 while (j < top2 && point[stk2[j]].x <= point[stk1[i]].x) { 79 res += (point[stk2[j]].x - lastx) * (tmp1 - tmp2); 80 lastx = point[stk2[j]].x; 81 ++j; 82 if (j < top2) tmp2 = std::max(point[stk2[j]].y, point[stk2[j - 1]].y); 83 else tmp2 = point[stk2[j - 1]].y; 84 } 85 res += (point[stk1[i]].x - lastx) * (tmp1 - tmp2); 86 lastx = point[stk1[i]].x; 87 ++i; 88 tmp1 = std::min(point[stk1[i]].y, point[stk1[i - 1]].y); 89 } 90 return res; 91 }
正常版本:
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <iomanip> 5 #include <cmath> 6 #include <algorithm> 7 8 typedef long long LL; 9 const LL INF = 0x3f3f3f3f3f3f3f3f; 10 struct Point { 11 LL x, y; 12 Point(LL _x = 0, LL _y = 0):x(_x), y(_y) {}; 13 bool operator <(const Point &) const; 14 } point[100010]; 15 int N; 16 17 LL calculate_perimeter(); 18 LL calculate_area(); 19 20 int main() { 21 #ifndef ONLINE_JUDGE 22 freopen("2146.in", "r", stdin); 23 freopen("2146.out", "w", stdout); 24 #endif 25 std::ios::sync_with_stdio(false); 26 std::cin >> N; 27 for (int i = 0; i < N; i++) 28 std::cin >> point[i].x >> point[i].y; 29 std::sort(point, point + N); 30 std::cout << calculate_perimeter() << std::endl << calculate_area() << std::endl; 31 32 return 0; 33 } 34 bool Point::operator <(const Point &p) const { return x == p.x ? y < p.y : x < p.x; } 35 LL calculate_perimeter() { 36 LL maxx = -INF, minx = INF, maxy = -INF, miny = INF; 37 for (int i = 0; i < N; i++) { 38 maxx = std::max(maxx, point[i].x); 39 minx = std::min(minx, point[i].x); 40 maxy = std::max(maxy, point[i].y); 41 miny = std::min(miny, point[i].y); 42 } 43 return (maxx - minx + maxy - miny) << 1; 44 } 45 LL calculate_area() { 46 int stk1[100010], top1 = 0, stk2[100010], top2 = 0; 47 LL res = 0, maxy = -INF, miny = INF; 48 for (int i = 0; i < N; i++) { 49 while (top1 > 0 && point[i].y > point[stk1[top1 - 1]].y && maxy > point[stk1[top1 - 1]].y) 50 --top1; 51 stk1[top1++] = i; 52 maxy = std::max(maxy, point[i].y); 53 while (top2 > 0 && point[i].y < point[stk2[top2 - 1]].y && miny < point[stk2[top2 - 1]].y) 54 --top2; 55 stk2[top2++] = i; 56 miny = std::min(miny, point[i].y); 57 } 58 LL tmp1 = point[stk1[0]].y, tmp2 = point[stk2[0]].y; 59 for (int i = 0, j = 0, lastx = point[0].x; i < top1;) { 60 while (j < top2 && point[stk2[j]].x <= point[stk1[i]].x) { 61 res += (point[stk2[j]].x - lastx) * (tmp1 - tmp2); 62 lastx = point[stk2[j]].x; 63 ++j; 64 if (j < top2) tmp2 = std::max(point[stk2[j]].y, point[stk2[j - 1]].y); 65 else tmp2 = point[stk2[j - 1]].y; 66 } 67 res += (point[stk1[i]].x - lastx) * (tmp1 - tmp2); 68 lastx = point[stk1[i]].x; 69 ++i; 70 tmp1 = std::min(point[stk1[i]].y, point[stk1[i - 1]].y); 71 } 72 return res; 73 }