uva1475 Jungle Outpost

229 篇文章 0 订阅
137 篇文章 0 订阅

注意到我们并不需要知道总部到底建在哪,只需要求出至少删掉的点数就可以了。
因此可以二分答案,删掉的一定是一段连续的点,于是总共有 O(n) 种删法,每种删法对应一个半平面。判断交是否为空集即可。
因为得到的这些直线是有序的,并不需要每次额外排序,复杂度可以做到 O(nlogn)

#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
const int maxn=200010;
const double eps=1e-8;
int cmp(double x)
{
    if (x>eps) return 1;
    if (fabs(x)<=eps) return 0;
    return -1;
}
struct Vector
{
    double x,y;
    Vector operator + (const Vector &v) const
    {
        return (Vector){x+v.x,y+v.y};
    }
    Vector operator - (const Vector &v) const
    {
        return (Vector){x-v.x,y-v.y};
    }
    Vector operator * (const double &k) const
    {
        return (Vector){x*k,y*k};
    }
    double ang() const
    {
        return atan2(y,x);
    }
}a[maxn],p[maxn];
typedef Vector Point;
double dot(Vector v,Vector u)
{
    return v.x*u.x+v.y*u.y;
}
double cross(Vector v,Vector u)
{
    return v.x*u.y-v.y*u.x;
}
struct Line
{
    Point p;
    Vector v;
    bool operator < (const Line &l) const
    {
        return cmp(v.ang()-l.v.ang())==-1;
    }
}f[maxn],t[maxn],que[maxn];
bool onleft(Point p,Line l)
{
    return cmp(cross(l.v,p-l.p))==1;
}
Point intersection(Line l1,Line l2)
{
    Vector v=l1.p-l2.p;
    double t=cross(l2.v,v)/cross(l1.v,l2.v);
    return l1.p+l1.v*t;
}
int n;
int ok(int k)
{
    int hd,tl,x;
    for (int i=1;i<=n;i++) t[i]=(Line){a[i+k+1],a[i]-a[i+k+1]};
    for (int i=n+1;i<=2*n;i++) t[i]=t[i-n];
    x=n+1;
    for (int i=n+2;i<=2*n;i++)
        if (t[i]<t[x]) x=i;
    for (int i=1;i<=n;i++) f[i]=t[x-i+1];
    que[hd=tl=1]=f[1];
    for (int i=2;i<=n;i++)
    {
        while (hd<tl&&!onleft(p[tl-1],f[i])) tl--;
        while (hd<tl&&!onleft(p[hd],f[i])) hd++;
        if (!(que[tl]<f[i])&&!(f[i]<que[tl]))
        {
            if (!onleft(p[tl-1],f[i])) que[tl]=f[i];
        }
        else que[++tl]=f[i];
        if (hd<tl) p[tl-1]=intersection(que[tl-1],que[tl]);
    }
    while (hd<tl&&!onleft(p[tl-1],que[hd])) tl--;
    return tl-hd<=1;
}
void solve()
{
    int l,r,mid;
    for (int i=1;i<=n;i++) scanf("%lf%lf",&a[i].x,&a[i].y);
    for (int i=n+1;i<=2*n+1;i++) a[i]=a[i-n];
    l=1,r=n;
    while (l<r)
    {
        mid=(l+r)/2;
        if (ok(mid)) r=mid;
        else l=mid+1;
    }
    printf("%d\n",l);
}
int main()
{
    //freopen("b.in","r",stdin);
    while (scanf("%d",&n)==1) solve();
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值