【jzoj5094】【GDSOI2017第四轮模拟day3】【鸽子】【计算几何】

题目大意

养鸽人要监视他的鸽子,有n只鸽子站在平面上,他可以在m个给定的点上设置监视器,如果一只鸽子在某个监视器上或者在两个监视器所连直线上或者在三个监视器所连直线的三角形内则其就咕咕咕了,现在养鸽人要让所有鸽子咕咕咕,请问他最少需要设置多少监视器。

解题思路

本题程序少考虑了很多问题,所以代码有很多bug需要读者手动修,这里提供正确的思路。

本题程序基于监视器全部在监视器组成的凸包上。

错误的思路

当监视器全部在监视器组成的凸包上,我们在凸包上对每个i求一个j,使i,j在所有鸽子的右边,由于j有单调性,所以复杂度是nm的,有了这个之后我们可以枚举一个必选点,贪心地跳,显然能跳尽量跳。

正确的思路

由于监视器不在同一个凸包上,考虑对鸽子做凸包,对于每个监视器,对于每一个监视器在凸包上暴力找出临界点,枚举凸包上一个点使用前一个和后一个点对当前点的向量与枚举点的向量的位置关系,可以知道是否是凸包切线,暴力枚举另一个监视器对切线做叉积即可判断是否合法,对可选的点对连边,相当于找一个最短的自环,将自己到自己设为正无穷,跑floyd即可。

错误的code

#include
#include
#include
#define LL long long
#define ULL unsigned long long
#define fo(i,j,k) for(LL i=j;i<=k;i++)
using namespace std;
LL const mn=1e5+9,mm=500,inf=1e9+7;
LL n,m,st[mm],next[mm];
struct rec{
    LL x,y;
};
rec a[mn],b[mm];
bool cmp(rec x,rec y){
    return atan2(x.y,x.x)+1e-6y.y,y.x);
}
LL cross(LL ax,LL ay,LL bx,LL by){
    return 1ll*ax*by-1ll*bx*ay;
}
bool chack(LL x,LL y){
    fo(i,1,n)
if(cross(b[y].x-b[x].x,b[y].y-b[x].y,a[i].x-b[x].x,a[i].y-b[x].y)<0)return 0;
    return 1;
}
int main(){
    //freopen("pigeon.in","r",stdin);
    //freopen("pigeon.out","w",stdout);
    freopen("d.in","r",stdin);
    freopen("d.out","w",stdout);
    scanf("%lld%lld",&n,&m);
    fo(i,1,n)scanf("%lld%lld",&a[i].x,&a[i].y);
    LL nx=inf,ny=inf;
    fo(i,1,m){
        scanf("%lld%lld",&b[i].x,&b[i].y);
        if((b[i].y.y==ny)&&((b[i].x.x,ny=b[i].y;
    }
    nx-=10,ny-110;
    fo(i,1,n)a[i].x-=nx,a[i].y-=ny;
    fo(i,1,m)b[i].x-=nx,b[i].y-=ny;
    sort(b+1,b+m+1,cmp);
    fo(i,1,m){
        while((st[0]>1)&&(cross(b[i].x-b[st[0]-1].x,b[i].y-b[st[0]-1].y,
            b[st[0]].x-b[st[0]-1].x,b[st[0]].y-b[st[0]-1].y)>=0))st[0]--;
        st[++st[0]]=i;
    }
    LL j=2,ans=m;
    fo(i,1,st[0]){
        if(i==j)j=i%st[0]+1;
        while(chack(st[i],st[j%st[0]+1]))j=j%st[0]+1;
        //if(!chack(i,j))
        //  ans=-1;
        next[i]=j;
    }
    if(ans==-1){
        printf("-1");
        return 0;
    }
    fo(i,1,st[0]){
        LL j=i,tmp=1;
        while(next[j]>j)
            j=next[j],tmp++;
        j=next[j];tmp++;
        while((next[j]>j)&&(next[j];
        ans=min(ans,tmp);
    }
    printf("%lld",ans);
    return 0;
}

你可能感兴趣的:(计算几何,jzoj)