UVA 1475 Jungle Outpost(二分+半平面交)

来源:互联网 发布:mac mini 不更新 编辑:程序博客网 时间:2024/05/29 12:04

UVA 1475 Jungle Outpost(二分+半平面交)

http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=4221

题意:

       在丛林中有n个瞭望台,形参了一个凸n多边形.这些瞭望台的保护范围就是这个凸多边形内的任意点. 敌人进攻时,会炸掉一些瞭望台,使得总部暴露在那些剩下的瞭望台的凸包之外.你的任务是选一个点作为总部,使得敌人需要炸坏的瞭望台数目尽量多. n个瞭望台按顺时针顺序输入.

分析:刘汝佳<<训练指南>> P281例题12

       如果敌人只有一颗炸弹,炸掉一个顶点后,不会暴露在外面的是一条有向直线的”左边”. 每条直线代表一个半平面,这样所有的这种直线就形成了一个半平面交. 我们就要看这个交集是否是非空的了.

       如果敌人有多个炸弹,他应该怎么炸才是最优呢? 这多个炸弹肯定是炸毁连续的几个顶点才最好.(自己画图比较一下) 所以这些炸弹又形成了一个行的半平面,我们依然看所有半平面是否存在交集即可.

       如果存在交集,说明敌人炸弹不够,还要炸更多的瞭望台才能使得我们在任何地方建立总部都会被暴露.

       所以我们二分敌人炸弹的数目mid,然后对于每个mid来构建半平面.求半平面的交集,看交集是否为空即可.

AC代码:

#include<cstdio>#include<cstring>#include<algorithm>#include<cmath>using namespace std;//精度控制const double eps=1e-10;int dcmp(double x){    if(fabs(x)<eps) return 0;    return x<0?-1:1;}//点struct Point{    double x,y;    Point(){}    Point(double x,double y):x(x),y(y){}};//向量typedef Point Vector;//点-点==向量Vector operator-(Point A,Point 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 p){    return Vector(A.x*p, A.y*p);}//叉积double Cross(Vector A,Vector B){    return A.x*B.y-A.y*B.x;}//有方向的直线struct Line{    Point p;    Vector v;    double ang;    Line(){}    Line(Point p,Vector v):p(p),v(v)    {        ang=atan2(v.y,v.x);    }    bool operator<(const Line &L)const    {        return ang<L.ang;    }};//判断点p是否在直线L左边bool OnLeft(Line L,Point p){    return Cross(L.v,p-L.p)>0;}//得到a与b两直线的交点Point GetIntersection(Line a,Line b){    Vector u=a.p-b.p;    double t=Cross(b.v,u)/Cross(a.v,b.v);    return a.p+a.v*t;}//返回半平面交的凸多边形poly节点集合int HalfplaneIntersection(Line *L,int n,Point *poly){    sort(L,L+n);    int first=0,last=0;    Point *p=new Point[n];    Line *q=new Line[n];    q[0]=L[0];    for(int i=1;i<n;i++)    {        while(first<last && !OnLeft(L[i],p[last-1])) last--;        while(first<last && !OnLeft(L[i],p[first])) first++;        q[++last]=L[i];        if(fabs(Cross(q[last].v,q[last-1].v))<eps)        {            last--;            if(OnLeft(q[last],L[i].p)) q[last]=L[i];        }        if(first<last) p[last-1]=GetIntersection(q[last-1],q[last]);    }    while(first<last && !OnLeft(q[first],p[last-1])) last--;    if(last-first<=1 ) return 0;    p[last]=GetIntersection(q[last],q[first]);    int m=0;    for(int i=first;i<=last;i++) poly[m++]=p[i];    return m;}/***以上为刘汝佳模板***/const int maxn=50000+5;Point p[maxn],poly[maxn];Line L[maxn];int main(){    int n;    while(scanf("%d",&n)==1)    {        for(int i=0;i<n;i++)            scanf("%lf%lf",&p[i].x,&p[i].y);        if(n==3)//三角形的话,直接删除一个点即可        {            printf("1\n");            continue;        }        reverse(p,p+n);//将所有顶点逆时针存放        //当炸掉n-2个连续的点时,半平面交肯定是空        int left=1,right=n-2;        while(right>left)        {            int mid=left+(right-left)/2;            for(int i=0;i<n;i++)                L[i]=Line(p[i],p[(i+1+mid)%n]-p[i]);            int m=HalfplaneIntersection(L,n,poly);            //m>0表示半平面交非空,那么需要加炸弹            if(m>0) left=mid+1;            else right=mid;        }        printf("%d\n",left);    }    return 0;}

0 0
原创粉丝点击