ZJOI 2008 瞭望塔 半平面交

该博客介绍了ZJOI 2008年竞赛中关于瞭望塔问题的解决方案,通过计算几何中的半平面交方法,确定能覆盖整个村庄的瞭望塔最低高度。题目要求在考虑整数坐标和有向面积的情况下,找到一次分段函数的最小值,博主分享了实现半平面交的代码,并指出针对此问题存在更为简洁的解法。
摘要由CSDN通过智能技术生成

题意:

给出一个以n个点为轮廓的村庄,在村庄任意位置放一个瞭望塔,使瞭望塔能看到村庄的所有位置,求瞭望塔最低高度。


思路:

考虑轮廓的每一条边,要看到这条边就必须在这条边以上的一个半平面内,因此求半平面交即可,样例图:



不妨将半平面交与地面上的直线看成分段函数,分别为f(x)与g(x),则所求即为h(x) = f(x) - g(x)的最小值,由于f(x)与g(x)均为一次分段函数,故h(x)也是一次分段函数,其最值仅可能在每一段的端点处取到。


注意:

1)输入的坐标为整数,注意转为double

2)叉积代表有向面积,写的时候要想清楚方向


由于是第一次写半平面交,根据老人家的模板写的,其实由于本题的特殊性可以写得更简单(例如直线可用斜截式),但这样的写法更具一般性,代码:

#include <cstdio>
#include <algorithm>
#include <cmath>

#define For(i,j,k) for(int i = j;i <= k;i++)
#define dcmp(x) (x > eps ? 1 : (x < -eps ? -1 : 0))

using namespace std;

const int N = 310;
const double eps = 1e-8;

struct Point{
    double x, y;

    Point(){}
    Point(double X, double Y):x(X), y(Y){}
    bool operator < (const Point& A) const{
        return x < A.x;
    }

};

typedef Point Vector;

Vector operator - (const Point &A, const Point &B){return Vector(A.x - B.x, A.y - B.y);}
Point operator + (const Point &A, const Vector &V){return Point(A.x + V.x, A.y + V.y);}
Vector operator * (const Vector &V, double k){return Vector(V.x * k, V.y * k);}
double Cross(const Vector &A, const Vector &B){return A.x * B.y - A.y * B.x;}

struct Line{
    Point P;
    Vector v;
    double ang;

    Line(){}
    Line(const Point& A, const Point& B){
        v = B - A;
        P = A;
        ang = atan2(v.y, v.x);
    }

    bool operator <(const Line& A) const{
        return ang < A.ang;
    }
};

Point Intersection(Line& A, Line& B){
    Vector v = A.P - B.P;
    double s = Cross(B.v, v) / Cross(A.v, B.v);
    return A.P + A.v * s;
}

bool Onleft(Line& L, Point& P){
    return Cross(L.v, P - L.P) > 0;
}

int n, m;
Line q[N], L[N];
Point p[N], land[N];

void HalfplaneIntersection(){
    int l = 1, r = 1;
    sort(L + 1, L + n + 1);
    q[l] = L[1];
    For(i,2,n){
        while(l < r && !Onleft(L[i], p[r-1])) r--;
        while(l < r && !Onleft(L[i], p[l])) l++;
        q[++r] = L[i];
        if(l < r && !dcmp(Cross(q[r].v, q[r-1].v))){
            r--;
            if(Onleft(q[r], L[i].P)) q[r] = L[i];
        }
        if(l < r) p[r-1] = Intersection(q[r-1], q[r]);
    }
    while(l < r && !Onleft(q[l], p[r-1])) r--;
    p[r] = Intersection(q[r], q[l]);
    For(i,l,r) p[i - l + 1] = p[i];
    m = r - l + 1;
}

int x[N], y[N];
int main(){
    scanf("%d", &n);
    For(i,1,n) scanf("%d", &x[i]);
    For(i,1,n) scanf("%d", &y[i]), land[i] = Point(x[i], y[i]);
    For(i,1,n-1) L[i] = Line(land[i], land[i+1]);
    L[n] = Line(Point(1e12, 1e12), Point(-1e12, 1e12));
    HalfplaneIntersection();
    sort(p + 1, p + m + 1);
    double Ans = 1e12;
    For(i,1,n)
        For(j,1,m-1)
            if(dcmp(x[i] - p[j].x) >= 0 && dcmp(x[i] - p[j+1].x) <= 0){
                Ans = min(Ans, p[j].y + (p[j+1].y - p[j].y) / (p[j+1].x - p[j].x) * (x[i] - p[j].x) - y[i]);
                break;
            }
    For(j,1,m)
        For(i,1,n-1)
            if(dcmp(p[j].x - x[i]) >= 0 && dcmp(p[j].x - x[i+1]) <= 0){
                Ans = min(Ans, p[j].y - (1.0 * y[i] + 1.0 * (y[i+1] - y[i]) / (x[i+1] - x[i]) * (p[j].x - x[i])));
                break;
            }
    printf("%.3lf\n", Ans);
    return 0;
}



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
资源包主要包含以下内容: ASP项目源码:每个资源包中都包含完整的ASP项目源码,这些源码采用了经典的ASP技术开发,结构清晰、注释详细,帮助用户轻松理解整个项目的逻辑和实现方式。通过这些源码,用户可以学习到ASP的基本语法、服务器端脚本编写方法、数据库操作、用户权限管理等关键技术。 数据库设计文件:为了方便用户更好地理解系统的后台逻辑,每个项目中都附带了完整的数据库设计文件。这些文件通常包括数据库结构图、数据表设计文档,以及示例数据SQL脚本。用户可以通过这些文件快速搭建项目所需的数据库环境,并了解各个数据表之间的关系和作用。 详细的开发文档:每个资源包都附有详细的开发文档,文档内容包括项目背景介绍、功能模块说明、系统流程图、用户界面设计以及关键代码解析等。这些文档为用户提供了深入的学习材料,使得即便是从零开始的开发者也能逐步掌握项目开发的全过程。 项目演示与使用指南:为帮助用户更好地理解和使用这些ASP项目,每个资源包中都包含项目的演示文件和使用指南。演示文件通常以视频或图文形式展示项目的主要功能和操作流程,使用指南则详细说明了如何配置开发环境、部署项目以及常见问题的解决方法。 毕业设计参考:对于正在准备毕业设计的学生来说,这些资源包是绝佳的参考材料。每个项目不仅功能完善、结构清晰,还符合常见的毕业设计要求和标准。通过这些项目,学生可以学习到如何从零开始构建一个完整的Web系统,并积累丰富的项目经验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值