POJ 3384 Feng Shui(计算几何の半平面交+最远点对)
Description
Feng shui is the ancient Chinese practice of placement and arrangement of space to achieve harmony with the environment. George has recently got interested in it, and now wants to apply it to his home and bring harmony to it.
There is a practice which says that bare floor is bad for living area since spiritual energy drains through it, so George purchased two similar round-shaped carpets (feng shui says that straight lines and sharp corners must be avoided). Unfortunately, he is unable to cover the floor entirely since the room has shape of a convex polygon. But he still wants to minimize the uncovered area by selecting the best placing for his carpets, and asks you to help.
You need to place two carpets in the room so that the total area covered by both carpets is maximal possible. The carpets may overlap, but they may not be cut or folded (including cutting or folding along the floor border) — feng shui tells to avoid straight lines.
Input
The first line of the input file contains two integer numbers n and r — the number of corners in George’s room (3 ≤ n ≤ 100) and the radius of the carpets (1 ≤ r ≤ 1000, both carpets have the same radius). The following nlines contain two integers xi and yi each — coordinates of the i-th corner (−1000 ≤ xi, yi ≤ 1000). Coordinates of all corners are different, and adjacent walls of the room are not collinear. The corners are listed in clockwise order.
Output
Write four numbers x1, y1, x2, y2 to the output file, where (x1, y1) and (x2, y2) denote the spots where carpet centers should be placed. Coordinates must be precise up to 4 digits after the decimal point.
If there are multiple optimal placements available, return any of them. The input data guarantees that at least one solution exists.
题目大意:给一个凸多边形围成的房子,顺时针给出点,再给两块半径为r的地毯,要求地毯覆盖面积最大且地毯不能切割or折叠,求地毯最大面积覆盖的时候地毯的圆心坐标,任意输出一组解
思路:房子所有边向内移动r,得到一个凸包,凸包上的最远点对即答案之一
PS:数据在http://neerc.ifmo.ru/past/index.html上面有,虽然很多人说这题JPS有问题,但我在WA了无数次之后发现其实还是自己的代码有问题(打错了一个变量名囧)……
暴力枚举最远点对(好牛逼的数据量):
- #include <cstdio>
- #include <cstring>
- #include <cmath>
- #include <algorithm>
- using namespace std;
- #define EPS 1e-8
- #define MAXN 1000
- inline int sgn(double x) {
- if(fabs(x) < EPS) return ;
- return x > ? : -;
- }
- struct Point {
- double x, y;
- Point(double xx = , double yy = ): x(xx), y(yy) {}
- bool operator == (const Point &b) const {
- return sgn(x - b.x) == && sgn(y - b.y) == ;
- }
- };
- //cross
- inline double operator ^ (const Point &a, const Point &b) {
- return a.x * b.y - a.y * b.x;
- }
- inline Point operator - (const Point &a, const Point &b) {
- return Point(a.x - b.x, a.y - b.y);
- }
- struct Line {
- Point s, e;
- double ag;
- };
- struct polygon {
- Point v[MAXN];
- int n;
- } pg, res;
- inline double dist(Point &a, Point &b) {
- return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
- }
- inline double Cross(Point o, Point s, Point e) {
- return (s - o) ^ (e - o);
- }
- //cross_point
- Point operator * (const Line &a, const Line &b) {
- Point res;
- double u = Cross(a.s, a.e, b.s), v = Cross(a.e, a.s, b.e);
- res.x = (b.s.x * v + b.e.x * u)/(u + v);
- res.y = (b.s.y * v + b.e.y * u)/(u + v);
- return res;
- }
- int parallel(Line a, Line b) {
- double u = (a.e.x - a.s.x) * (b.e.y - b.s.y) - (a.e.y - a.s.y) * (b.e.x - b.s.x);
- return sgn(u) == ;
- }
- inline void set_vector(double x1, double y1, double x2, double y2, Line &v) {
- v.s.x = x1; v.s.y = y1;
- v.e.x = x2; v.e.y = y2;
- v.ag = atan2(y2 - y1, x2 - x1);
- }
- Line vct[MAXN], deq[MAXN];
- bool cmp(const Line &a, const Line &b) {
- if(sgn(a.ag - b.ag) == )
- return sgn(Cross(b.s, b.e, a.s)) < ;
- return a.ag < b.ag;
- }
- int half_planes_cross(Line *v, int vn) {
- int i, n;
- //sort(v, v + vn, cmp);
- for(i = n = ; i < vn; ++i) {
- if(sgn(v[i].ag - v[i-].ag) == ) continue;
- v[n++] = v[i];
- }
- int head = , tail = ;
- deq[] = v[], deq[] = v[];
- for(i = ; i < n; ++i) {
- if(parallel(deq[tail - ], deq[tail]) || parallel(deq[head], deq[head + ]))
- return false;
- while(head < tail && sgn(Cross(v[i].s, v[i].e, deq[tail - ] * deq[tail])) > )
- --tail;
- while(head < tail && sgn(Cross(v[i].s, v[i].e, deq[head] * deq[head + ])) > )
- ++head;
- deq[++tail] = v[i];
- }
- while(head < tail && sgn(Cross(deq[head].s, deq[head].e, deq[tail - ] * deq[tail])) > )
- --tail;
- while(head < tail && sgn(Cross(deq[tail].s, deq[tail].e, deq[head] * deq[head + ])) > )
- ++head;
- if(tail <= head + ) return false;
- res.n = ;
- for(i = head; i < tail; ++i)
- res.v[res.n++] = deq[i] * deq[i + ];
- res.v[res.n++] = deq[head] * deq[tail];
- res.n = unique(res.v, res.v + res.n) - res.v;
- res.v[res.n] = res.v[];
- return true;
- }
- void moving(Line v[], int vn, double r) {
- for(int i = ; i < vn; ++i) {
- double dx = v[i].e.x - v[i].s.x, dy = v[i].e.y - v[i].s.y;
- dx = dx / dist(v[i].s, v[i].e) * r;
- dy = dy / dist(v[i].s, v[i].e) * r;
- v[i].s.x += dy; v[i].e.x += dy;
- v[i].s.y -= dx; v[i].e.y -= dx;
- }
- }
- int main() {
- int n;
- double r;
- while(scanf("%d%lf", &n, &r) != EOF) {
- for(int i = ; i < n; ++i) scanf("%lf%lf", &pg.v[i].x, &pg.v[i].y);
- pg.v[n] = pg.v[];
- for(int i = ; i < n; ++i)
- set_vector(pg.v[i].x, pg.v[i].y, pg.v[i+].x, pg.v[i+].y, vct[i]);
- moving(vct, n, r);
- half_planes_cross(vct, n);
- int ix = , jx = ;
- double maxdis = ;
- for(int i = ; i < res.n; ++i) {
- for(int j = ; j < res.n; ++j) {
- if(i == j) continue;
- double t = dist(res.v[i], res.v[j]);
- if(sgn(t - maxdis) > ) {
- maxdis = t;
- ix = i, jx = j;
- }
- }
- }
- printf("%.4f %.4f %.4f %.4f\n", res.v[ix].x, res.v[ix].y, res.v[jx].x, res.v[jx].y);
- }
- }
旋转卡壳求最远点对:
- #include <cstdio>
- #include <cstring>
- #include <cmath>
- #include <algorithm>
- using namespace std;
- #define EPS 1e-8
- #define MAXN 1000
- inline int sgn(double x) {
- if(fabs(x) < EPS) return ;
- return x > ? : -;
- }
- struct Point {
- double x, y;
- Point(double xx = , double yy = ): x(xx), y(yy) {}
- bool operator == (const Point &b) const {
- return sgn(x - b.x) == && sgn(y - b.y) == ;
- }
- };
- //cross
- inline double operator ^ (const Point &a, const Point &b) {
- return a.x * b.y - a.y * b.x;
- }
- inline Point operator - (const Point &a, const Point &b) {
- return Point(a.x - b.x, a.y - b.y);
- }
- struct Line {
- Point s, e;
- double ag;
- };
- struct polygon {
- Point v[MAXN];
- int n;
- } pg, res;
- inline double dist(Point &a, Point &b) {
- return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
- }
- inline double Cross(Point o, Point s, Point e) {
- return (s - o) ^ (e - o);
- }
- //cross_point
- Point operator * (const Line &a, const Line &b) {
- Point res;
- double u = Cross(a.s, a.e, b.s), v = Cross(a.e, a.s, b.e);
- res.x = (b.s.x * v + b.e.x * u)/(u + v);
- res.y = (b.s.y * v + b.e.y * u)/(u + v);
- return res;
- }
- int parallel(Line a, Line b) {
- double u = (a.e.x - a.s.x) * (b.e.y - b.s.y) - (a.e.y - a.s.y) * (b.e.x - b.s.x);
- return sgn(u) == ;
- }
- inline void set_vector(double x1, double y1, double x2, double y2, Line &v) {
- v.s.x = x1; v.s.y = y1;
- v.e.x = x2; v.e.y = y2;
- v.ag = atan2(y2 - y1, x2 - x1);
- }
- Line vct[MAXN], deq[MAXN];
- bool cmp(const Line &a, const Line &b) {
- if(sgn(a.ag - b.ag) == )
- return sgn(Cross(b.s, b.e, a.s)) < ;
- return a.ag < b.ag;
- }
- int half_planes_cross(Line *v, int vn) {
- int i, n;
- //sort(v, v + vn, cmp);
- for(i = n = ; i < vn; ++i) {
- if(sgn(v[i].ag - v[i-].ag) == ) continue;
- v[n++] = v[i];
- }
- int head = , tail = ;
- deq[] = v[], deq[] = v[];
- for(i = ; i < n; ++i) {
- if(parallel(deq[tail - ], deq[tail]) || parallel(deq[head], deq[head + ]))
- return false;
- while(head < tail && sgn(Cross(v[i].s, v[i].e, deq[tail - ] * deq[tail])) > )
- --tail;
- while(head < tail && sgn(Cross(v[i].s, v[i].e, deq[head] * deq[head + ])) > )
- ++head;
- deq[++tail] = v[i];
- }
- while(head < tail && sgn(Cross(deq[head].s, deq[head].e, deq[tail - ] * deq[tail])) > )
- --tail;
- while(head < tail && sgn(Cross(deq[tail].s, deq[tail].e, deq[head] * deq[head + ])) > )
- ++head;
- if(tail <= head + ) return false;
- res.n = ;
- for(i = head; i < tail; ++i)
- res.v[res.n++] = deq[i] * deq[i + ];
- res.v[res.n++] = deq[head] * deq[tail];
- res.n = unique(res.v, res.v + res.n) - res.v;
- res.v[res.n] = res.v[];
- return true;
- }
- void moving(Line v[], int vn, double r) {
- for(int i = ; i < vn; ++i) {
- double dx = v[i].e.x - v[i].s.x, dy = v[i].e.y - v[i].s.y;
- dx = dx / dist(v[i].s, v[i].e) * r;
- dy = dy / dist(v[i].s, v[i].e) * r;
- v[i].s.x += dy; v[i].e.x += dy;
- v[i].s.y -= dx; v[i].e.y -= dx;
- }
- }
- int ix, jx;
- double dia_roataing_calipers() {
- double dia = ;
- ix = jx = ;
- int q = ;
- for(int i = ; i < res.n; ++i) {
- while(sgn(Cross(res.v[i+], res.v[i], res.v[q+]) - Cross(res.v[i+], res.v[i], res.v[q])) > )
- q = (q + ) % res.n;
- if(sgn(dist(res.v[i], res.v[q]) - dia) > ) {
- dia = dist(res.v[i], res.v[q]);
- ix = i; jx = q;
- }
- if(sgn(dist(res.v[i+], res.v[q]) - dia) > ) {
- dia = dist(res.v[i+], res.v[q]);
- ix = i+; jx = q;
- }
- }
- return dia;
- }
- int main() {
- int n;
- double r;
- while(scanf("%d%lf", &n, &r) != EOF) {
- for(int i = ; i < n; ++i) scanf("%lf%lf", &pg.v[i].x, &pg.v[i].y);
- pg.v[n] = pg.v[];
- for(int i = ; i < n; ++i)
- set_vector(pg.v[i].x, pg.v[i].y, pg.v[i+].x, pg.v[i+].y, vct[i]);
- moving(vct, n, r);
- half_planes_cross(vct, n);
- dia_roataing_calipers();
- printf("%.4f %.4f %.4f %.4f\n", res.v[ix].x, res.v[ix].y, res.v[jx].x, res.v[jx].y);
- }
- }
POJ 3384 Feng Shui(计算几何の半平面交+最远点对)的更多相关文章
- POJ 3384 Feng Shui (半平面交)
Feng Shui Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 3743 Accepted: 1150 Speci ...
- POJ 3384 Feng Shui(半平面交向内推进求最远点对)
题目链接 题意 : 两个圆能够覆盖的最大多边形面积的时候两个圆圆心的坐标是多少,两个圆必须在多边形内. 思路 : 向内推进r,然后求多边形最远的两个点就是能覆盖的最大面积. #include < ...
- poj 3384 Feng Shui (Half Plane Intersection)
3384 -- Feng Shui 构造半平面交,然后求凸包上最远点对. 这题的题意是给出一个凸多边形区域,要求在其中放置两个半径为r的圆(不能超出凸多边形区域),要求求出两个圆心,使得多边形中没有被 ...
- POJ 3384 Feng Shui 半平面交
题目大意:一个人很信"Feng Shui",他要在房间里放两个圆形的地毯. 这两个地毯之间可以重叠,可是不能折叠,也不能伸到房间的外面.求这两个地毯可以覆盖的最大范围.并输出这两个 ...
- POJ 3384 放地毯【半平面交】
<题目链接> 题目大意: 给出一个凸多边形的房间,根据风水要求,把两个圆形地毯铺在房间里,不能折叠,不能切割,可以重叠.问最多能覆盖多大空间,输出两个地毯的圆心坐标.多组解输出其中一个,题 ...
- POJ 3384 Feng Shui
http://poj.org/problem?id=3384 题意:给一个凸包,求往里面放两个圆(可重叠)的最大面积时的两个圆心坐标. 思路:先把凸包边往内推R,做半平面交,然后做旋转卡壳,此时得到最 ...
- POJ 3384 Feng Shui --直线切平面
题意:房间是一个凸多边形,要在里面铺设两条半径为r的圆形地毯,可以重叠,现在要求分别铺设到哪,使地毯所占的地面面积最大. 解法:要使圆形地毯所占面积最大,圆形地毯一定是与边相切的,这样才能使尽量不重叠 ...
- POJ 3384 Feng Shui 凸包直径 + 半平面交
G++一直没有过了 换成 C++果断A掉了...It's time to bet RP. 题意:给一个多边形,然后放进去两个圆,让两个圆的覆盖面积尽量最大,输出两个圆心的坐标. 思路:将多边形的边向里 ...
- poj 3335 Rotating Scoreboard(半平面交)
Rotating Scoreboard Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 6420 Accepted: 25 ...
随机推荐
- 个人免签收款接口 bufpay.com 支持限额设置
有产品希望收款分布到不同的手机,每个当手机达到某一限额以后就停止改手机的收款. bufpay.com 近期上线了收款限额设置功能,配置界面如下图: 每个手机微信或支付宝可以单独设置每日限额,如果该手机 ...
- 浅析MySQL 5.7组复制技术(Group Replication)
Group Replication is know as an up to date HA(High Availablity) solution which is supported in ...
- 利用MyFlash闪回丢失数据
MyFlash is an open source tool released by Meituan-Dianping which can be used to flashback MyS ...
- js扩展String.prototype.format字符串拼接的功能
1.题外话,有关概念理解:String.prototype 属性表示 String原型对象.所有 String 的实例都继承自 String.prototype. 任何String.prototype ...
- Java并发编程:浅析几种线程安全模型 [转]
多线程编程一直是老生常谈的问题,在Java中,随着JDK的逐渐发展,JDK提供给我们的并发模型也越来越多,本文摘取三例使用不同原理的模型,分析其大致原理.目录如下: 1.COW之CopyOnWrite ...
- HTML5开篇定义(更新中)
以下介绍的两种属性是为后面的属性支持左铺垫,大概一看就OK了. 通用属性 id 用于为HTML元素指定唯一标识 style 用于为HTML元素指定CSS指定样式 class 用于匹配CSS样式的cla ...
- 微信小程序 —— 仿制豆瓣(一)
先预览一下效果 欢迎扫码查看 码云地址:https://gitee.com/mk_23/little_chen_xu.git 预览完成,首先进入app.json文件中配置参数,主要就是配置我们要用的页 ...
- layui sleect获取value值
<div class="layui-form-item"> <label for="username" class="layui-f ...
- HDFS原理
1 . NameNode 概述 a. NameNode 是 HDFS 的核心. b. NameNode 也称为 Master. c. NameNode 仅存储 HDFS 的元数据:文件系统中所有文件的 ...
- opencv3 学习五 - 合并与分割通道
合并与分割通道 程序如下 #include "opencv2/opencv.hpp" using namespace cv; int main() { Mat original = ...