Sicily 1955/2612. Fort

1955. Fort

Constraints

Time Limit: 2 secs, Memory Limit: 32 MB

Description

Planet Cartesian is dominated by the great kingdom Terran. There are n forts in Terran, where its people live a peaceful life. And there is also a river named Yellow River across the territory of Terran, which has raised thousands and thousands of Terran’s people. To be more specific, in Cartesian coordinates, the Yellow River can be viewed as the x-axis, and each fort can regarded as a point (x, y), where x and y are both integers.

However, the peaceful life has been interrupted by Protoss recently. Protoss soldiers frequently appear outside the forts, attack Terran’s people, and then disappear rapidly. Many people have been hurt. So, the Federal Committee of Terran has decided to build a great wall surrounding all the forts, to protect people from Protoss’s attack. Of course, to concentrate defence power, the area surrounded by the great wall should be minimized.

To make things worse, as the Yellow River is quite important to Terran’s people, it’s necessary to make sure that part of the river (one or more segments, or points) is inside/on the great wall.

Now, as the chief architect of Terran, you should make a plan to build the great wall. Come on!

Input

Input may contain several test cases. The first line is a positive integer T, (1<=T<=20), the number of test cases below. For each test case, the first line is a positive integer, n, (1<=n<=100000) the number of forts. And the following n lines are coordinates of forts, x and y, (x and y are both integers with absolute value no more than 10000).

Output

For each test case, output the minimum area that must be surrounded by the great wall, round to 3 digits after the decimal point.

Sample Input

1
3
-1 1
0 2
1 1

Sample Output

2.000

// Problem#: 1955
// Submission#: 3593362
// The source code is licensed under Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License
// URI: http://creativecommons.org/licenses/by-nc-sa/3.0/
// All Copyright reserved by Informatic Lab of Sun Yat-sen University
#include <stdio.h>
#include <string.h>
#include <math.h>

const int MAXN = 100005;
const int MAXV = 20005;
const double EPS = 1e-4;
const double INF = 1e12;

class node {
public:
    node() {}
    node(double px, double py) {
        x = px;
        y = py;
    }
    node& operator = (node b) {
        x = b.x;
        y = b.y;
        return *this;
    }
    double x, y;
};

int n;
double minY[MAXV], maxY[MAXV];
node p[MAXN];

void preProcess() {
    int i;
    for (i = 0; i < MAXV; i++) minY[i] = INF, maxY[i] = -INF;
    for (i = 0; i < n; i++) {
        int x = (int)p[i].x;
        if (minY[x] > p[i].y) minY[x] = p[i].y;
        if (maxY[x] < p[i].y) maxY[x] = p[i].y;
    }
}

double crossProduct(node a, node b, node c) {
    return (b.x - a.x) * (c.y - a.y) - (c.x - a.x) * (b.y - a.y);
}

void findConvexHull() {
    node stackUp[MAXV], stackDown[MAXV];
    int topUp, topDown;
    preProcess();
    int i;
    for (i = 0; i < MAXV; i++)
        if (maxY[i] > -INF) break;
    stackUp[0] = node(i, maxY[i]);
    stackDown[0] = node(i, minY[i]);
    topUp = topDown = 0;
    for (i++; i < MAXV; i++) {
        if (maxY[i] > -INF) {
            while (topUp >= 1 && crossProduct(stackUp[topUp - 1], stackUp[topUp], node(i, maxY[i])) >= -EPS)
                topUp--;
            stackUp[++topUp] = node(i, maxY[i]);
            while (topDown >= 1 && crossProduct(stackDown[topDown - 1], stackDown[topDown], node(i, minY[i])) <= EPS)
                topDown--;
            stackDown[++topDown] = node(i, minY[i]);
        }
    }
    n = 0;
    for (i = 0; i <= topDown; i++) p[n++] = stackDown[i];
    int from = topUp, to = 0;
    if (stackUp[topUp].x == stackDown[topDown].x && stackUp[topUp].y == stackDown[topDown].y)
        from--;
    if (stackUp[0].x == stackDown[0].x && stackUp[0].y == stackDown[0].y)
        to++;
    for (i = from; i >= to; i--) p[n++] = stackUp[i];
}

double calcPolygonArea(node p[], int n) {
    double res = 0;
    for (int i = 0; i < n; i++)
        res += p[i].x * p[(i + 1) % n].y - p[i].y * p[(i + 1) % n].x;
    res *= 0.5;
    return fabs(res);
}

double calcTriangleArea(node a, node b, node c) {
    double res = 0;
    res += a.x * b.y - a.y * b.x;
    res += b.x * c.y - b.y * c.x;
    res += c.x * a.y - c.y * a.x;
    res *= 0.5;
    return fabs(res);
}

bool intersectXaxis(node p[], int n) {
    bool upper = false, lower = false;
    for (int i = 0; i < n; i++) {
        if (fabs(p[i].y) < EPS) return true;
        if (p[i].y > EPS) upper = true;
        else lower = true;
    }
    return upper && lower;
}

double calcXaxisIntersection(node a, node b) {
    if (a.y >= -EPS && b.y - a.y >= -EPS || a.y <= EPS && b.y - a.y <= EPS)
        return INF;
    return ((0 - a.y) * (b.x - a.x)) / (b.y - a.y) + a.x;
}

double MoveAndCalc(node p[], int n, double area) {
    double res, sum;
    int from = -1, to;
    double px = INF;
    for (int i = 0; i < n; i++) {
        double x = calcXaxisIntersection(p[i], p[(i + 1) % n]);
        if (from < 0 || x < px) {
            px = x;
            from = i;
        }
    }
    sum = 0;
    for (to = from; to != (from + n - 1) % n; to = (to + 1) % n) {
        double t = crossProduct(p[to], p[(to + 1) % n], node(px, 0));
        if (t >= EPS) break;
        sum += p[to].x * p[(to + 1) % n].y - p[to].y * p[(to + 1) % n].x;
    }
    res = area - (sum + p[to].x * p[from].y - p[to].y * p[from].x) / 2 + calcTriangleArea(p[from], node(px, 0), p[to]);
    do {
        sum -= p[from].x * p[(from + 1) % n].y - p[from].y * p[(from + 1) % n].x;
        from = (from + 1) % n;
        px = calcXaxisIntersection(p[from], p[(from + 1) % n]);
        if (px - INF >= -EPS) break;
        for (; ; to = (to + 1) % n) {
            double t = crossProduct(p[to], p[(to + 1) % n], node(px, 0));
            if (t >= -EPS) break;
            sum += p[to].x * p[(to + 1) % n].y - p[to].y * p[(to + 1) % n].x;
        }
        double t = area - (sum + p[to].x * p[from].y - p[to].y * p[from].x) / 2 + calcTriangleArea(p[from], node(px, 0), p[to]);
        if (t < res) res = t;
    } while (true);
    return res;
}

double solve() {
    int i;
    double res, area;
    findConvexHull();
    area = calcPolygonArea(p, n);
    if (intersectXaxis(p, n)) return area;
    if (p[0].y < -EPS) {
        for (i = 0; i + i < n; i++) {
            node temp = p[i];
            p[i] = p[n - 1 - i];
            p[n - 1 - i] = temp;
        }
        for (i = 0; i < n; i++) p[i].y = -p[i].y;
    }
    res = MoveAndCalc(p, n, area);
    for (i = 0; i + i < n; i++) {
        node temp = p[i];
        p[i] = p[n - 1 - i];
        p[n - 1 - i] = temp;
    }
    for (i = 0; i < n; i++) p[i].x = MAXV - 1 - p[i].x;
    double t = MoveAndCalc(p, n, area);
    if (t < res) res = t;
    return res;
}

int main() {
    int tn;
    scanf("%d", &tn);
    while (tn--) {
        scanf("%d", &n);
        for (int i = 0; i < n; i++) {
            scanf("%lf%lf", &p[i].x, &p[i].y);
            p[i].x += MAXV / 2;
        }
        printf("%.3lf\n", solve());
    }
    return 0;
}                                 


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值