Sicily 1143. 选址

1143. 选址

Constraints

Time Limit: 10 secs, Memory Limit: 32 MB

Description

很久以前,在世界的某处有一个形状为凸多边形的小岛,岛上的居民们决定建一个祭坛,居民们认为祭坛的位置离岛的顶点处越远越好。

你的任务是求凸多边形内一点,使其与各顶点的距离中最短的距离最远,点在边上也可以。

这样的点可能有多个,你只需输出这些点与各顶点的最短距离。

Input

第一行是一个整数N(3≤N≤100)。

接下来N行按逆时针顺序给出每个顶点的坐标,每行包含2个实数,表示顶点的横坐标和纵坐标(坐标绝对值小于10000)。

Output

输出一个实数,表示凸多边形内一点与各顶点的距离中最短的距离的最大值。

Sample Input

30 29 07 7

Sample Output

4.893

Problem Source

ZSUACM Team Member

// Problem#: 1143
// Submission#: 3587467
// 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 <math.h>
#include <string.h>

const int maxn = 100;

long n;

struct point {
    double x, y;
}p[maxn + 1];

struct line {
    double a, b, c;
};

double ans;
point ans_p;
char ans_k;

void check(point p1, char k) {
    long i;
    double cur, min;
    for (i = 0; i < n; i++) {
        cur = (p[i].x - p1.x) * (p[i].x - p1.x) + (p[i].y - p1.y) * (p[i].y - p1.y);
        if (i == 0 || cur < min) min = cur;
    }
    if (min > ans) {
        ans = min;
        ans_p = p1; 
        ans_k = k;
    }
}

line straightline(point p1, point p2) {
    line l;
    l.a = p2.y - p1.y;
    l.b = p1.x - p2.x;
    l.c = -l.a * p1.x - l.b * p1.y;
    return l;
}

line midline(point p1, point p2) {
    line l;
    l.a = p1.x - p2.x;
    l.b = p1.y - p2.y;
    l.c = -l.a * (p1.x + p2.x) / 2.0 - l.b * (p1.y + p2.y) / 2.0;
    return l;
}

bool cross(point p1, point p2, line l) {
    return ((l.a * p1.x + l.b * p1.y + l.c) * (l.a * p2.x + l.b * p2.y + l.c) <= 0);
}

point crosspoint(line l1, line l2) {
    point p1;
    p1.x = (-l1.c * l2.b + l1.b * l2.c) / (l1.a * l2.b - l1.b * l2.a);
    p1.y = (-l1.a * l2.c + l1.c * l2.a) / (l1.a * l2.b - l1.b * l2.a);
    return p1;
}

void process() {
    long i, j, k;
    line l, l2;
    point la, lb, c;
    ans = 0;
    p[n] = p[0];
    for (i = 0; i < n; i++)
        for (j = i + 1; j < n; j++) {
            l = midline(p[i], p[j]);
            for (k = i; k != j; k = (k + 1) % n) {
                if (cross(p[k], p[k + 1], l)) {
                    la = crosspoint(straightline(p[k], p[k + 1]), l);
                    break;
                }
            }
            if (k == j) printf("ERROR\n");
            for (k = j; k != i; k = (k + 1) % n) {
                if (cross(p[k], p[k + 1], l)) {
                    lb = crosspoint(straightline(p[k], p[k + 1]), l);
                    break;
                }
            }
            if (k == i) printf("ERROR\n");
            check(la, 'e');
            check(lb, 'e');
            for (k = 0; k < n; k++) 
                if (k != i && k != j) {
                    l2 = midline(p[i], p[k]);
                    if (cross(la, lb, l2)) {
                        c = crosspoint(l2, l);
                        check(c, 'i');
                    }
                }
        }
    printf("%.3lf\n", sqrt(ans));
}

int main() {
    while (scanf("%ld", &n) == 1 && n != 0) {
        for (int i = 0; i < n; i++) scanf("%lf%lf", &p[i].x, &p[i].y);
        process();
    }
    return 0;
}                                 


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值