• POJ 3525 /// 半平面交 模板


    题目大意:

    给定n,接下来n行逆时针给定小岛的n个顶点

    输出岛内离海最远的点与海的距离

    半平面交模板题

    将整个小岛视为由许多半平面围成

    那么以相同的比例缩小这些半平面

    一直到缩小到一个点时 那个点就是离海最远的点

    #include <cstdio>
    #include <cmath>
    #include <vector>
    #include <algorithm>
    using namespace std;
    const double eps=1e-10;
    double add(double a,double b) {
        if(abs(a+b)<eps*(abs(a)+abs(b))) return 0;
        return a+b;
    }
    struct P{
        double x,y;
        P(){};
        P(double _x,double _y):x(_x),y(_y){};
        P operator - (P p) {
            return P(add(x,-p.x),add(y,-p.y)); }
        P operator + (P p) {
            return P(add(x,p.x),add(y,p.y)); }
        P operator * (double d) {
            return P(x*d,y*d); }
        double dot (P p) {
            return add(x*p.x,y*p.y); }
        double det (P p) {
            return add(x*p.y,-y*p.x); }
    }p[205], py[205];
    struct L {
        P p, v;  // p为直线上一点 v为单位方向向量
        double ang; // 极角
        L(){};
        L(P _p,P _v):p(_p),v(_v){ ang=atan2(v.y,v.x); }
        bool operator < (const L& b)const {
            return ang<b.ang;
        }
    }l[205], lp[205];
    int n;
    double lenV(P p) {
        return sqrt(p.dot(p));
    }  // 求p的长度 
    P NV(P p) {
        double len=lenV(p);
        return P(-p.y/len,p.x/len);
    }  // 求向量p的单位向量
    P ins(L a,L b) {
        return a.p+a.v*((b.v).det(a.p-b.p)/(a.v).det(b.v));
    }  // 求a与b的交点 
    bool onLeft(L l,P p) {
        return (l.v).det(p-l.p)>0;
    }  // 判断p是否在l的左侧
    int insHp() {
        sort(l,l+n); // 按极角排序
        int head,tail;
        vector <P> pi(n*2);  // 交点
        vector <L> li(n*2);  // 半平面
        li[head=tail=0]=l[0];
        for(int i=1;i<n;i++) {
            while(head<tail && !onLeft(l[i],pi[tail-1])) tail--;
            while(head<tail && !onLeft(l[i],pi[head])) head++;
            // 之前的半平面的交点是否都在当前半平面的左边 否则去掉
            li[++tail]=l[i]; // 将当前半平面加入
                                                                                                                                                                                                                                                                                                                                                                                                
            if(abs((li[tail].v).det(li[tail-1].v))<eps) {// 若加入后发现与上一个半平面平行
                tail--; // 先把当前半平面去掉
                if(onLeft(li[tail],l[i].p)) // 若当前半平面在上一个半平面左边
                    li[tail]=l[i]; // 说明当前半平面可将上一个覆盖
            }
            if(head<tail) pi[tail-1]=ins(li[tail-1],li[tail]);
            // 加入当前半平面新产生的交点
            // tail-1 是与上一个半平面产生的交点
        }
        while(head<tail && !onLeft(li[head],pi[tail-1])) tail--;
        // 当前交点是否在一开始的半平面的左边 否则说明当前被开始的半平面覆盖
        if(tail-head<=1) return 0;
        pi[tail]=ins(li[tail],li[head]); // 加入与第一个半平面的交点
    int m=0; for(int i=head;i<=tail;i++) py[m++]=pi[i]; // 将半平面的内核顶点存入 return m; // 返回顶点数 } int main() { while(~scanf("%d",&n)) { if(n==0) break; for(int i=0;i<n;i++) scanf("%lf%lf",&p[i].x,&p[i].y); for(int i=0;i<n;i++) { lp[i].p=p[(i+1)%n]-p[i]; lp[i].v=NV(lp[i].p); } double le=0,ri=20000; while(ri-le>eps) { // 二分 double mid=le+(ri-le)/2; for(int i=0;i<n;i++) l[i]=L(p[i]+lp[i].v*mid,lp[i].p); // 以mid比例 收缩多边形 int m=insHp(); if(!m) ri=mid; else le=mid; } printf("%.6f ",le); } return 0; }
  • 相关阅读:
    一个屌丝程序猿的人生(七十二)
    一个屌丝程序猿的人生(七十一)
    一个屌丝程序猿的人生(七十)
    一个屌丝程序猿的人生(六十九)
    一个屌丝程序猿的人生(六十八)
    一个屌丝程序猿的人生(六十七)
    Target-Action回调模式
    KVC & KVO
    ARC内存管理机制详解
    Objective-C中把URL请求的参数转换为字典
  • 原文地址:https://www.cnblogs.com/zquzjx/p/9689292.html
Copyright © 2020-2023  润新知