Hrbustoj 1429 二分+计算几何

时间:2023-03-10 08:37:46
Hrbustoj 1429 二分+计算几何

http://www.bubuko.com/infodetail-1121744.html 在这个上面学习了方法 如果要判断巨量的点 就应该使用二分法

思路是先从a[1] a[n] a[2]来判断是否可能在图形内 如果这个都通不过就不用再判断下边的了

然后从 2 到 n 开始二分 确定两个相邻向量 使寻找点必在这两个向量的夹角里

然后就是点是否在三角形内了 由于已经判断了两条边了 最后只判断第三条即可

一开始 二分的while条件写的是r-l!=0 最后得到的效果是 点必定在r l向量的夹角内

然而超时 很不理解QAQ

后来学习了网上的办法 设定条件l<r 这样最后得到的l其实是等于r的 点在l l-1的夹角内

学习的方法里提到了一点 位运算比乘除运算快非常多

分别尝试了一下 位运算 485ms 正常乘除 541ms

自己写的代码

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<map>
#include<math.h>
using namespace std;
struct point
{
double x,y;
};
double cross(point a,point b,point c)
{
return (b.x-a.x)*(c.y-a.y)-(c.x-a.x)*(b.y-a.y);
}
int main(){
int n;
while(~scanf("%d",&n))
{
point a[n+1];
for(int i=1;i<=n;i++)
{
scanf("%lf%lf",&a[i].x,&a[i].y);
}
bool ok=true;
int m;
scanf("%d",&m);
point p[m];
for(int i=0;i<m;i++)
{
scanf("%lf%lf",&p[i].x,&p[i].y); }
for(int i=0;i<m;i++)
{
if(cross(a[1],p[i],a[2])<=0||cross(a[1],a[n],p[i])<=0)
{
ok=false;
break;
}
int l=2;
int r=n;
int m;
while(l<r)
{
m=(r+l)/2;/// m=(r+l)>>1 更快一些
if(cross(a[1],p[i],a[m])<=0)
{
r=m;
}
else l=m+1;
}
if(cross(a[l],p[i],a[l-1])>=0)
{
ok=false;
break;
}
} if(ok==true)
printf("YES\n");
else printf("NO\n");
}
}