zoukankan      html  css  js  c++  java
  • 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 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 ≤ xiyi ≤ 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 x1y1x2y2 to the output file, where (x1y1) and (x2y2) 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.


    题意:

    在一个有 n 个点的凸包形状房间中,要放两个半径为 r 的圆形地毯,要求这两个地毯覆

    盖地板的面积越大越好,求两个地毯圆心的位置。


    先把凸包缩小r,就变成找圆心了,当然是最远点了,直接枚举点对就好了
    
    
    变成逆时针直接reverse一下就好了
     
    然而本题太恶心了.....不说了自己看discuss
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    #include <vector>
    using namespace std;
    typedef long long ll;
    const int N=205;
    const double INF=1e3+5;
    const double eps=1e-10;
    inline int read(){
        char c=getchar();int x=0,f=1;
        while(c<'0'||c>'9'){if(c=='-')f=-1; c=getchar();}
        while(c>='0'&&c<='9'){x=x*10+c-'0'; c=getchar();}
        return x*f;
    }
    
    inline int sgn(double x){
        if(abs(x)<eps) return 0;
        else return x<0?-1:1;
    }
    
    struct Vector{
        double x,y;
        Vector(double a=0,double b=0):x(a),y(b){}
        bool operator <(const Vector &a)const{
            return sgn(x-a.x)<0||(sgn(x-a.x)==0&&sgn(y-a.y)<0);
        }
        void print(){printf("%lf %lf
    ",x,y);}
    };
    typedef Vector Point;
    Vector operator +(Vector a,Vector b){return Vector(a.x+b.x,a.y+b.y);}
    Vector operator -(Vector a,Vector b){return Vector(a.x-b.x,a.y-b.y);}
    Vector operator *(Vector a,double b){return Vector(a.x*b,a.y*b);}
    Vector operator /(Vector a,double b){return Vector(a.x/b,a.y/b);}
    bool operator ==(Vector a,Vector b){return sgn(a.x-b.x)==0&&sgn(a.y-b.y)==0;}
    double Dot(Vector a,Vector b){return a.x*b.x+a.y*b.y;}
    double Cross(Vector a,Vector b){return a.x*b.y-a.y*b.x;}
    double Len(Vector a){return sqrt(Dot(a,a));}
    Vector Normal(Vector a){
        return Vector(-a.y,a.x);//counterClockwise
    }
    struct Line{
        Point s,t;
        Line(){}
        Line(Point a,Point b):s(a),t(b){}
    };
    bool isLSI(Line l1,Line l2){
        Vector v=l1.t-l1.s,u=l2.s-l1.s,w=l2.t-l1.s;
        return sgn(Cross(v,u))!=sgn(Cross(v,w));
    }
    Point LI(Line a,Line b){
        Vector v=a.s-b.s,v1=a.t-a.s,v2=b.t-b.s;
        double t=Cross(v2,v)/Cross(v1,v2);
        return a.s+v1*t;
    }
    
    void iniPolygon(Point p[],int &n,double inf){
        n=0;
        p[++n]=Point(-inf,-inf);
        p[++n]=Point(inf,-inf);
        p[++n]=Point(inf,inf);
        p[++n]=Point(-inf,inf);
    }
    Point t[N];int tn;
    void CutPolygon(Point p[],int &n,Point a,Point b){//get the left of a->b
        tn=0;
        Point c,d;
        for(int i=1;i<=n;i++){
            c=p[i],d=p[i%n+1];
            if(sgn(Cross(b-a,c-a))>=0) t[++tn]=c;
            if(isLSI(Line(a,b),Line(c,d)))
                t[++tn]=LI(Line(a,b),Line(c,d));
        }
        n=tn;for(int i=1;i<=n;i++) p[i]=t[i];
    }
    
    int n,r,m;
    Point p[N],q[N];
    Line L[N];
    void ChangePolygon(Point p[],int n,double x){
        p[n+1]=p[1];
        for(int i=1;i<=n;i++){
            Vector v=Normal(p[i+1]-p[i])*x/Len(p[i+1]-p[i]);
            L[i]=Line(p[i]+v,p[i+1]+v);
        }
    }
    
    int main(int argc, const char * argv[]){
        while(scanf("%d%d",&n,&r)!=EOF){
            for(int i=1;i<=n;i++) scanf("%lf%lf",&p[i].x,&p[i].y);
            iniPolygon(q,m,INF);
            reverse(p+1,p+1+n);
            ChangePolygon(p,n,r);
            Point a,b;double mx=0;
            for(int i=1;i<=n;i++) CutPolygon(q,m,L[i].s,L[i].t);
            for(int i=1;i<=m;i++)
                for(int j=1;j<=m;j++) if(sgn(Len(q[j]-q[i])-mx)>=0){
                    mx=Len(q[j]-q[i]);
                    a=q[i];b=q[j];
                }
            if(a.x>b.x) swap(a,b);
            printf("%.4f %.4f %.4f %.4f
    ",a.x,a.y,b.x,b.y);
        }
    }
     
  • 相关阅读:
    C#.NET常见问题(FAQ)-如何在不同窗体之间传递值
    C#.NET常见问题(FAQ)-如何不显示窗口的关闭按钮
    C#.NET常见问题(FAQ)-如何判断两个类是否相同类型
    C#.NET常见问题(FAQ)-如何判断某个字符是否为汉字
    C#.NET常见问题(FAQ)-如何改变字符串编码
    C# 多线程编程 ThreadStart ParameterizedThreadStart
    C# 线程调用主线程中的控件
    LINQ to XML 编程基础
    LINQ to XML 建立,读取,增,删,改
    WinForm 自动完成控件实例代码简析
  • 原文地址:https://www.cnblogs.com/candy99/p/6358995.html
Copyright © 2011-2022 走看看