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

题目大意

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

解题思路

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

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

错误的思路

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

正确的思路

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

错误的code

#include<cmath>
#include<cstdio>
#include<algorithm>
#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-6<atan2(y.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<ny)||((b[i].y==ny)&&((b[i].x<nx))))nx=b[i].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]<i))
            j=next[j],tmp++;
        ans=min(ans,tmp);
    }
    printf("%lld",ans);
    return 0;
}
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看REaDME.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值