题解 P3738 【[HAOI2014]穿越封锁线】
一道比较正常的计算几何题。
思路
思路很清晰,就是模拟先把所有点和边与y轴的交点排序,每次判断是否会导致这个点与多边形的位置关系(是否在多边形内)。
问题
第一反应肯定是“每穿过一条边或一个点与多边形位置关系都会改变”,然后收获一页WA。发现不是穿过每一个点时都会改变与多边形的位置关系。
解决方式
事实上这是因为点分两种,一种是像第一张图片一样,穿过会改变位置关系,另一种是像第二张图片,穿过不会改变位置关系,经过瞪眼认真思考,我们发现这是与连接这个点的两条线段与y轴正方向的位置关系决定的(此处将人的出发点作为原点)如果两条线段在y轴的同侧,则穿过点时不改变位置关系,反之则改变。
解决点的问题之后就是推出每条线段与y轴交点位置(如果有)并且统计。
注:还有一个坑点是初始位置可能在多边形内部,特判一下即可。
代码
代码中的“状态”即为点与多边形的位置关系。
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=60;
struct node{
double a;//交点y坐标
int flag;//是否改变状态
}e[N];
int n,a,b,x[N],y[N],cnt,ans;
double now;
bool cmp(node x,node y){
return x.a<y.a;
}
int main(){
freopen("lg.in","r",stdin);
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d%d",&x[i],&y[i]);
scanf("%d%d",&a,&b);
for(int i=1;i<=n;i++)
x[i]-=a,y[i]-=b;//把人的初始坐标设为原点
x[0]=x[n],y[0]=y[n];
for(int i=1;i<=n;i++){
if(x[i]==0){//点
e[++cnt].a=y[i];
e[cnt].flag=1;
if((x[i-1]-x[i])*(x[i]-x[i+1])<0) e[cnt].flag=0;//如果连接一个点的两条边属于y轴同一侧则无需改变状态
}
if(x[i]*x[i-1]<0){//边
if(x[i]>x[i-1])
e[++cnt].a=(double)(y[i]-y[i-1])/(x[i]-x[i-1])*(-x[i-1])+y[i-1];
else
e[++cnt].a=(double)(y[i-1]-y[i])/(x[i-1]-x[i])*(-x[i])+y[i];//计算边与y轴交点坐标
e[cnt].flag=1;//一定会改变状态
}
}
double now=0,last=0;
sort(e+1,e+cnt+1,cmp);
for(int i=1,opt=0;i<=cnt;i++){
if(e[i].flag){
if(e[i].a<0){
opt^=1;
continue;
}
if(opt)
now+=e[i].a-last;
else
last=e[i].a;
opt^=1;
}
}
int ans=now;
printf("%d\n",ans);
return 0;
}