zoukankan      html  css  js  c++  java
  • BZOJ2146 Construct

    题目大意

    给出一个多边形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,也就是说实际上维护的是一个“峰”(大概不叫单调栈了):

    clip_image002

    还有就是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 }
  • 相关阅读:
    LeetCode-195
    中文屋子与图灵测试谁对?
    leedcode-122
    Java 网络编程
    Java File类与IO流
    Java 异常
    Java 多线程
    Java Collection集合
    Java 常用API (第二部分)
    Java 日期时间与unix时间戳之间转换
  • 原文地址:https://www.cnblogs.com/Rhein-E/p/10265529.html
Copyright © 2011-2022 走看看