UVALive 4992 Jungle Outpost(半平面交判存)

Jungle Outpost

Time limit: 15.000 seconds

Description

There is a military base lost deep in the jungle. It is surrounded by n watchtowers with ultrasonic generators. In this problem watchtowers are represented by points on a plane.

Watchtowers generate ultrasonic field and protect all objects that are strictly inside the towers‘ convex hull. There is no tower strictly inside the convex hull and no three towers are on a straight line.

The enemy can blow up some towers. If this happens, the protected area is reduced to a convex hull of the remaining towers.

The base commander wants to build headquarters inside the protected area. In order to increase its security, he wants to maximize the number of towers that the enemy needs to blow up to make the headquarters unprotected.

Input

The input file contains several test cases, each of them as described below.

The first line of each one of the cases contains a single integer n(3n50000) -- the number of watchtowers. The next n lines of the input file contain the Cartesian coordinates of watchtowers, one pair of coordinates per line. Coordinates are integer and do not exceed106 by absolute value. Towers are listed in the order of traversal of their convex hull in clockwise direction.

Output

For each test case, write to the output file the number of watchtowers the enemy has to blow up to compromise headquarters protection if the headquarters are placed optimally.

Sample Input

3
0 0
50 50
60 10
5
0 0
0 10
10 20
20 10
25 0

Sample Output

1
2

二分答案,判半平面交是否存在。注意:连续销毁几个点比分开销毁的做法更优。

建立半平面是用直线表示的 。然后直线的左边是代表有面积的,所以要注意下直线的向量方向。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <vector>
#include <queue>
#include <map>
#include <set>
#include <stack>
#include <algorithm>

using namespace std;

#define X first
#define Y second
#define root 1,n,1
#define lr rt<<1
#define rr rt<<1|1
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1

typedef long long LL;
typedef pair<int,int> pii;
const int N = 50050 ;
const int inf = 1e9+7;
const double eps = 1e-8;
int n ;

inline 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){};
    bool operator < ( const Point &a ) const {
        return dcmp(x-a.x) < 0 || ( dcmp(x-a.x)==0 && dcmp(y-a.y) < 0 );
    }
}e[N];
typedef Point Vector;
struct Line {
    Point p;
    Vector v ;          // directional vector
    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;
    }
};

Point operator - ( Point a , Point b ){ return Point(a.x-b.x,a.y-b.y); }
Point operator + ( Point a , Point b ){ return Point(a.x+b.x,a.y+b.y); }
Point operator * ( Point a , double p ){ return Point(a.x*p,a.y*p); }

inline double Cross(Point a , Point b ) { return a.x*b.y-a.y*b.x;}
bool OnLeft( Line L , Point p ) {
    return Cross( L.v , p-L.p ) > 0 ;
}

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;
}

bool HPI( Line* L , int n  ) {
    sort( L , L + n );
    int first , last ;          //deque ,
    Point *p = new Point[n];    //p[i] is q[i] and q[i+1] ‘s intersection point
    Line *q = new Line[n];
    q[first=last=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--;
    // delete useless plane
    if( last - first <= 1 ) return false ;
    return true ;
}

Line L[N];

bool ok( int num ) {
    int tot = 0 ;
    for( int i = 0 ; i < n ; ++i ) {
        L[tot++] = Line( e[(i+num+1)%n],e[i]-e[(i+num+1)%n] );   // convex in clockwise direction
    }
    if( !HPI(L,tot) ) return true ;
    return false ;
}

void Run() {

    for( int i = 0 ; i < n ; ++i ) {
        scanf("%lf%lf",&e[i].x,&e[i].y);
    }
    if( n == 3 ) { puts("1"); return ; }
    int ans = 0 , l = 0 , r = n - 3 ;
    while( l <= r ) {
        int mid = (l+r)>>1;
        if( ok(mid) )
            ans = mid , r = mid - 1 ;
        else
            l = mid + 1 ;
    }
    printf("%d\n",ans);
}

int main(){
    #ifdef LOCAL
        freopen("in.txt","r",stdin);
    #endif // LOCAL
    while( scanf("%d",&n)!=EOF ) Run();
}

时间: 2024-10-19 20:46:34

UVALive 4992 Jungle Outpost(半平面交判存)的相关文章

UVALive 4992 Jungle Outpost(半平面交)

题意:给你n个塔(点)形成一个顺时针的凸包,敌人可以摧毁任何塔,摧毁后剩下的塔再组成凸包 在开始的凸包内选一点为主塔,保证敌人摧毁尽量多塔时主塔都还在现在的凸包内,求出最多摧毁的塔 题解:这题关键就是选的主塔在不同的地方,敌人就会摧毁不同的塔来让你的主塔暴露 因此这样想,找出敌人摧毁不同的塔后形成的所有不同的凸包,再求出所有凸包的交就好 具体就是,首先枚举摧毁塔的个数k,再把摧毁任意k个塔所形成的所有不同的凸包求一个交,如果为空就代表了摧毁k个塔一定可以保证无论主塔在哪儿都可以暴露(关键) 而所

uvalive 7331 Hovering Hornet 半平面交+概率期望

题意:一个骰子在一个人正方形内,蜜蜂在任意一个位置可以出现,问看到点数的期望. 思路:半平面交+概率期望 1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<iostream> 5 #include<cstdlib> 6 #include<string> 7 #include<cmath> 8 #include<vector&

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

题意: 有n个瞭望塔构成一个凸n边形,敌人会炸毁一些瞭望台,剩下的瞭望台构成新的凸包.在凸多边形内部选择一个点作为总部,使得敌人需要炸毁的瞭望塔最多才能使总部暴露出来.输出敌人需要炸毁的数目. 分析: 在炸毁同样数量的瞭望塔时,如何爆破才能使暴露出的面积最大.那就是集中火力炸掉连续的几个瞭望塔.直觉上是这样的,我不会证明这个结论.因为是连续爆破,所以k次爆破后还保留的部分就是一个半平面,枚举这k个爆破点,如果这些半平面交非空则总部可以设在这里. k值是通过二分来确定的,下界是1,上界是n-3(这

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

题目链接:点击打开链接 思路:首先,我们要知道一个贪心结论:敌人如果有k个炸弹, 那么他一定是炸连续的k个点, 这样会使得炸的面积最大.  那么我们只要二分炸弹数mid,每隔mid个点重新建立一个平面, 仍然是n个平面, 代表n种可能情况, 那么如果他们的交存在, 那么司令部只要放在这个平面交的面积内就行了.  所以问题迎刃而解, 二分答案, 用半平面交判断答案是否可行. 细节参见代码: #include <cstdio> #include <cstring> #include &

poj1474Video Surveillance(半平面交)

链接 半平面交的模板题,判断有没有核.: 注意一下最后的核可能为一条线,面积也是为0的,但却是有的. 1 #include<iostream> 2 #include <stdio.h> 3 #include <math.h> 4 #define eps 1e-8 5 using namespace std; 6 const int MAXN=210; 7 int m; 8 double r; 9 int cCnt,curCnt;//此时cCnt为最终切割得到的多边形的顶

半平面交模板

摘自http://blog.csdn.net/accry/article/details/6070621 首先解决问题:什么是半平面? 顾名思义,半平面就是指平面的一半,我们知道,一条直线可以将平面分为两个部分,那么这两个部分就叫做两个半平面. 然后,半平面怎么表示呢? 二维坐标系下,直线可以表示为ax + by + c = 0,那么两个半平面则可以表示为ax + by + c >= 0 和ax + by + c < 0,这就是半平面的表示方法. 还有,半平面的交是神马玩意? 其实就是一个方程

半平面交 模板 poj 3335 poj 3130 poj 1474 判断半平面交是否为空集

半平面交模板 const double pi= acos(-1.0); #define arc(x) (x / 180 * pi) const double EPS = 1e-8; const int Max_N = 105; struct Point{ double x,y; Point(){} Point(double x, double y):x(x),y(y){} Point operator - (Point p){ return Point(x- p.x , y - p.y ) ;

POJ 3525 Most Distant Point from the Sea (半平面交向内推进+二分半径)

题目链接 题意 : 给你一个多边形,问你里边能够盛的下的最大的圆的半径是多少. 思路 :先二分半径r,半平面交向内推进r.模板题 1 #include <stdio.h> 2 #include <string.h> 3 #include <iostream> 4 #include <math.h> 5 const double eps = 1e-10 ; 6 7 using namespace std ; 8 9 struct node 10 { 11 do

poj2540Hotter Colder(半平面交)

链接 根据距离可以列得直线方程,附上初始矩形的四个顶点,依次用直线切割. 1 #include<iostream> 2 #include <stdio.h> 3 #include <math.h> 4 #include<cstring> 5 #include<algorithm> 6 #define eps 1e-8 7 using namespace std; 8 const int MAXN=1550; 9 int m; 10 double