• JZOJ 1082. 【GDOI2005】选址


    \(\text{Problem}\)

    很久以前,在世界的某处有一个形状为凸多边形的小岛,岛上的居民们决定建一个祭坛,居民们任务祭坛的位置离岛的顶点处越远越好。
    你的任务是求凸多边形内一点,使其与各顶点的距离中最短的距离最远,点在边上也可以。 这样的点可能有多个,你只需输出这些点与各顶点的最短距离。

    \(\text{Solution}\)

    非常经典的题
    以答案为半径做圆,满足圆心到所有点距离大于等于半径
    考虑二分半径,判断圆心存不存在
    枚举任意两点,考虑分别以此半径做圆交出的点(选取内部的点,叉积判断是否在内部)
    如果这点没有被所有圆覆盖,即这点到凸边形顶点的最短距离大于等于半径,说明圆心存在
    算交点用相似,如果没有交点考虑其在边上交出的点一样判断
    精度很神奇,不要用 \(\text{long double}\)
    本地过不了数据1 \(OJ\) 上却过了?!

    \(\text{Code}\)

    #include <cstdio>
    #include <algorithm>
    #include <cmath>
    #define RE register
    #define IN inline
    using namespace std;
    
    const int N = 105;
    const double eps = 1e-8;
    double area;
    int n;
    struct Vector{
    	double x, y;
    	IN Vector(double xx = 0, double yy = 0){x = xx, y = yy;}
    	IN Vector operator - (const Vector &B){return Vector(x - B.x, y - B.y);}
    	IN double operator * (const Vector &B){return fabs(x * B.y - y * B.x);}
    }p[N];
    
    IN double sqr(double x){return x * x;}
    IN double distance(Vector a, Vector b){return sqrt(sqr(a.x - b.x) + sqr(a.y - b.y));}
    IN double Area(Vector a, Vector b, Vector c){return (a - b) * (c - b);}
    IN double sum_Area(Vector a)
    {
    	double res = 0;
    	for(RE int i = 1; i < n; i++) res += Area(a, p[i], p[i + 1]);
    	return res + Area(a, p[n], p[1]);
    }
    IN int isIn(Vector a){if (fabs(sum_Area(a) - area) <= eps) return 1; return 0;}
    IN int OK(Vector a, double r)
    {
    	double res = 1e18;
    	for(RE int i = 1; i <= n; i++) res = min(res, distance(a, p[i]));
    	return res >= r;
    }
    
    IN int check(double r)
    {
    	for(RE int i = 1; i <= n; i++)
    		for(RE int j = 1; j < i; j++)
    		{
    			double d = distance(p[i], p[j]);
    			if (d > r * 2)
    			{
    				double k = (p[i].y - p[j].y) / (p[i].x - p[j].x), x, y;
    				y = min(p[i].y, p[j].y) + fabs(p[i].y - p[j].y) * r / d;
    				if (k > 0)
    				{
    					x = min(p[i].x, p[j].x) + fabs(p[i].x - p[j].x) * r / d;
    					if (OK(Vector{x, y}, r)) return 1;
    					x = p[i].x + p[j].x - x, y = p[i].y + p[j].y - y;
    					if (OK(Vector{x, y}, r)) return 1;
    				}
    				else{
    					x = max(p[i].x, p[j].x) - fabs(p[i].x - p[j].x) * r / d;
    					if (OK(Vector{x, y}, r)) return 1;
    					x = p[i].x + p[j].x - x, y = p[i].y + p[j].y - y;
    					if (OK(Vector{x, y}, r)) return 1;
    				}
    			}
    			else{
    				double w = sqrt(r * r - d * d / 4), k = w / d;
    				double dx = (p[i].x + p[j].x) / 2, dy = (p[i].y + p[j].y) / 2;
    				double x = dx - fabs(p[i].y - p[j].y) * k, y = dy + fabs(p[i].x - p[j].x) * k;
    				if (isIn(Vector{x, y}) && OK(Vector{x, y}, r)) return 1;
    				x = p[i].x + p[j].x - x, y = p[i].y + p[j].y - y;
    				if (isIn(Vector{x, y}) && OK(Vector{x, y}, r)) return 1;
    			}
    		}
    	return 0;
    }
    
    int main()
    {
    	scanf("%d", &n);
    	for(RE int i = 1; i <= n; i++) scanf("%lf%lf", &p[i].x, &p[i].y);
    	area = sum_Area(p[1]); double r = 0;
    	for(RE int i = 1; i <= n; i++)
    		for(RE int j = 1; j < i; j++) r = max(r, distance(p[i], p[j]));
    	double l = 0, mid = (l + r) / 2, ans;
    	for(RE int i = 0; i < 60; i++, mid = (l + r) / 2)
    		if (check(mid)) ans = mid, l = mid; else r = mid;
    	printf("%.3lf\n", ans);
    }
    
  • 相关阅读:
    带你梳理Roach全量恢复的整体流程
    为AR&VR黑科技:以“自由视角”360度尽展舞台唯美
    一个15年的架构师谈“如何成为一名优秀的解决方案架构师”
    SARIF:DevSecOps工具与平台交互的桥梁
    “蚂蚁牙黑”太火,想玩就用ModelArts做一个!
    图神经网络,这到底是个什么?
    Python 面向对象进阶
    Python 装饰器
    SQL 存储过程中事务回滚
    python 迭代器协议和生成器
  • 原文地址:https://www.cnblogs.com/leiyuanze/p/15819569.html
Copyright © 2020-2023  润新知