POJ 3384 Feng Shui

http://poj.org/problem?id=3384

题意:给一个凸包,求往里面放两个圆(可重叠)的最大面积时的两个圆心坐标。

思路:先把凸包边往内推R,做半平面交,然后做旋转卡壳,此时得到最大距离的点对,就是圆心坐标。

PS:最大长度的初始值要设置为负数,因为距离有可能退化到0,就像这组数据

4 1

0 0

2 0

2 2

0 2

#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<algorithm>
const double Pi=acos(-1);
double R;
int n,tot;
struct Point{
    double x,y;
    Point(){}
    Point(double x0,double y0):x(x0),y(y0){}
}p[200005];
struct Line{
    Point s,e;
    double slop;
    Line(){}
    Line(Point s0,Point e0):s(s0),e(e0){}
}L[200005],l[200005],c[200005];
int read(){
    int t=0,f=1;char ch=getchar();
    while (ch<‘0‘||ch>‘9‘){if (ch==‘-‘)f=-1;ch=getchar();}
    while (‘0‘<=ch&&ch<=‘9‘){t=t*10+ch-‘0‘;ch=getchar();}
    return t*f;
}
Point operator /(Point p1,double x){
    return Point(p1.x/x,p1.y/x);
}
Point operator *(Point p,double x){
    return Point(p.x*x,p.y*x);
}
double operator *(Point p1,Point p2){
    return p1.x*p2.y-p1.y*p2.x;
}
Point operator -(Point p1,Point p2){
    return Point(p1.x-p2.x,p1.y-p2.y);
}
Point operator +(Point p1,Point p2){
    return Point(p1.x+p2.x,p1.y+p2.y);
}
bool cmp(Line p1,Line p2){
    if (p1.slop!=p2.slop) return p1.slop<p2.slop;
    else return (p1.e-p1.s)*(p2.e-p1.s)<=0;
}
Point inter(Line p1,Line p2){
    double k1=(p2.e-p1.s)*(p1.e-p1.s);
    double k2=(p1.e-p1.s)*(p2.s-p1.s);
    double t=(k2)/(k1+k2);
    double x=p2.s.x+(p2.e.x-p2.s.x)*t;
    double y=p2.s.y+(p2.e.y-p2.s.y)*t;
    return Point(x,y);
}
bool jud(Line p1,Line p2,Line p3){
    Point p=inter(p1,p2);
    return (p-p3.s)*(p3.e-p3.s)>0;
}
void phi(){
    std::sort(l+1,l+1+tot,cmp);
    int cnt=1;
    for (int i=2;i<=tot;i++)
     if (l[i].slop!=l[i-1].slop)
      l[++cnt]=l[i];
    int L=1,R=2;c[L]=l[1];c[R]=l[2];
    for (int i=3;i<=cnt;i++){
        while (L<R&&jud(c[R],c[R-1],l[i])) R--;
        while (L<R&&jud(c[L],c[L+1],l[i])) L++;
        c[++R]=l[i];
    }
    while (L<R&&jud(c[R],c[R-1],c[L])) R--;
    while (L<R&&jud(c[L],c[L+1],c[R])) L++;
    tot=0;
    c[R+1]=c[L];
    for (int i=L;i<=R;i++)
     p[++tot]=inter(c[i],c[i+1]);
}
double sqr(double x){
    return x*x;
}
double dis(Point p){
    return sqrt(sqr(p.x)+sqr(p.y));
}
Point turn(Point p,double ang){
    double Cos=cos(ang),Sin=sin(ang);
    double x=Cos*p.x-Sin*p.y;
    double y=Cos*p.y+Sin*p.x;
    return Point(x,y);
}
Point e(Point p){
    double len=dis(p);p=p/len;return p;
}
double dis(Point p1,Point p2){
    return dis(p1-p2);
}
void rc(){
    p[tot+1]=p[1];
    int k=2;
    double mx=-1;
    Point ans1,ans2;
    for (int i=1;i<=tot;i++){
        while (fabs((p[i%tot+1]-p[i])*(p[k]-p[i]))<fabs((p[i%tot+1]-p[i])*(p[k%tot+1]-p[i]))) k=(k)%tot+1;
        if (mx<dis(p[i],p[k])){
            mx=dis(p[i],p[k]);
            ans1=p[i];
            ans2=p[k];
        }
    }
    printf("%.4f %.4f %.4f %.4f",ans1.x,ans1.y,ans2.x,ans2.y);
}
int main(){
    n=read(),R=read();
    for (int i=1;i<=n;i++) p[i].x=read(),p[i].y=read();
    for (int i=1;i<=n/2;i++) std::swap(p[i],p[n-i+1]);
    p[n+1]=p[1];
    for (int i=1;i<=n;i++)
     l[++tot]=Line(p[i],p[i+1]),l[tot].slop=atan2(l[tot].e.y-l[tot].s.y,l[tot].e.x-l[tot].s.x);
    for (int i=1;i<=n;i++){
     Point p=e(turn((l[i].e-l[i].s),Pi/2.0))*R;
     l[i].s=l[i].s+p;
     l[i].e=l[i].e+p;
    }
    phi();
    rc();
}
时间: 2024-12-30 04:12:03

POJ 3384 Feng Shui的相关文章

poj 3384 Feng Shui 半平面交的应用 求最多覆盖凸多边形的面积的两个圆 的圆心坐标

题目来源: http://poj.org/problem?id=3384 分析: 用半平面交将多边形的每条边一起向"内"推进R,得到新的多边形(半平面交),然后求多边形的最远两点. 代码如下: const double EPS = 1e-10; const int Max_N = 105 ; struct Point{ double x,y; Point(){} Point(double x, double y):x(x),y(y){} Point operator - (Point

POJ 3384 Feng Shui [半平面交]

Feng Shui Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 5537   Accepted: 1663   Special Judge Description Feng shui is the ancient Chinese practice of placement and arrangement of space to achieve harmony with the environment. George h

POJ 3384 Feng Shui(半平面交向内推进求最远点对)

题目链接 题意 : 两个圆能够覆盖的最大多边形面积的时候两个圆圆心的坐标是多少,两个圆必须在多边形内. 思路 : 向内推进r,然后求多边形最远的两个点就是能覆盖的最大面积. #include <stdio.h> #include <string.h> #include <math.h> #include <iostream> using namespace std ; struct node { double x,y ; }p[110],temp[110],

POJ 3384 Feng Shui --直线切平面

题意:房间是一个凸多边形,要在里面铺设两条半径为r的圆形地毯,可以重叠,现在要求分别铺设到哪,使地毯所占的地面面积最大. 解法:要使圆形地毯所占面积最大,圆形地毯一定是与边相切的,这样才能使尽量不重叠. 那么我们把所有边都向内推进r,那么形成的多边形,可知两个圆形地毯的中心就一定在这个多边形边界上,最优的情况下是在此新凸包的最远点对上. 初始多边形为(-1000,-1000)到(1000,1000)的矩形,那么我们可以模拟把每条边都推进,每次切出新的凸多边形,然后得出最后的凸多边形,然后n^2枚

poj 3384 半平面交

Feng Shui Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 5183   Accepted: 1548   Special Judge Description Feng shui is the ancient Chinese practice of placement and arrangement of space to achieve harmony with the environment. George h

POJ3384:Feng Shui——题解

http://poj.org/problem?id=3384 题目大意:给一个顺时针序的多边形,求在里面放半径为r的两个圆使得两圆覆盖的面积最大,求出这样的圆的坐标. ———————————————— 解题思路:将多边形内缩进r,然后求内核. 枚举点对然后根据点对距离判断是否覆盖面积最大即可. 注意:可能两圆重合. #include<cstdio> #include<queue> #include<cctype> #include<cstring> #inc

POJ 3384

题目大意: 给定一个多边形,给定一个圆的半径,要求在多边形中放置两个同样半径的圆,可相互覆盖,但不能超出多边形的范围,希望两个圆的面积覆盖和最大 输出任意一组满足的圆的圆心点 如果两个圆不相互覆盖,那么必然达到最大面积 如果相互覆盖,可以换一种方式考虑,因为两个圆是一样的,两个圆的距离越长,那么相互覆盖的面积必然越小 所以可以将多边形内推进半径的长度 然后在半平面交后得到的多边形中找到距离最远的两个点 仔细想一想可以知道多边形上最远距离的点,必然是两个顶点的距离 所以平方的方法就可以求解了 当然

POJ 3384 放地毯【半平面交】

<题目链接> 题目大意: 给出一个凸多边形的房间,根据风水要求,把两个圆形地毯铺在房间里,不能折叠,不能切割,可以重叠.问最多能覆盖多大空间,输出两个地毯的圆心坐标.多组解输出其中一个,题目保证至少可以放入一个圆. 解题分析: 因为放置的圆不能超出多边形的边界,所以先将该凸多边形的各个边长向内平移 r 的距离,然后对这些平移后的直线用半平面交去切割原多边形,切割后得到的区域就是两圆圆心所在的区域,然后遍历这个切割后的多边形的各个顶点,距离最远的两个顶点就是这两圆的圆心. #include<

[转] POJ几何分类

转自:http://blog.csdn.net/tyger/article/details/4480029 计算几何题的特点与做题要领:1.大部分不会很难,少部分题目思路很巧妙2.做计算几何题目,模板很重要,模板必须高度可靠.3.要注意代码的组织,因为计算几何的题目很容易上两百行代码,里面大部分是模板.如果代码一片混乱,那么会严重影响做题正确率.4.注意精度控制.5.能用整数的地方尽量用整数,要想到扩大数据的方法(扩大一倍,或扩大sqrt2).因为整数不用考虑浮点误差,而且运算比浮点快. 一.点