给定一个多边形,求一条竖直向上的射线与多边形相交的距离。(n leq 50)
Solution
求出与所有边的交点(包括端点),按 (y) 坐标升序排序
如果一个交点不是端点,我们就改变当前状态
如果一个交点是端点,则当这个点两侧的线段分居在射线左右两侧时才改变当前状态。注意这里的两侧是不严格的,也就是说如果其中一段与射线重合,那么就直接算作分居两侧。
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 105;
const double eps = 1e-6;
struct point {
double x,y;
bool operator < (const point &b) {
return y < b.y;
}
bool operator == (const point &b) {
return fabs(x-b.x)<eps && fabs(y-b.y)<eps;
}
void read() {
cin>>x>>y;
}
} p[N],q,oo;
double xmult(point p1,point p2,point p0){
return (p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y);
}
int same_side(point p1,point p2,point l1,point l2){
return xmult(l1,p1,l2)*xmult(l1,p2,l2)>eps;
}
int dots_inline(point p1,point p2,point p3){
return fabs(xmult(p1,p2,p3))<eps;
}
int dot_online_in(point p,point l1,point l2){
return fabs(xmult(p,l1,l2))<eps&&(l1.x-p.x)*(l2.x-p.x)<eps
&&(l1.y-p.y)*(l2.y-p.y)<eps;
}
int intersect_in(point u1,point u2,point v1,point v2){
if (!dots_inline(u1,u2,v1)||!dots_inline(u1,u2,v2))
return !same_side(u1,u2,v1,v2)&&!same_side(v1,v2,u1,u2);
return dot_online_in(u1,v1,v2)||dot_online_in(u2,v1,v2)||dot_online_in(v1,u1,u2)||dot_online_in(v2,u1,u2);
}
point intersection(point u1,point u2,point v1,point v2){
point ret=u1;
double t=((u1.x-v1.x)*(v1.y-v2.y)-(u1.y-v1.y)*(v1.x-v2.x))
/((u1.x-u2.x)*(v1.y-v2.y)-(u1.y-u2.y)*(v1.x-v2.x));
ret.x+=(u2.x-u1.x)*t;
ret.y+=(u2.y-u1.y)*t;
return ret;
}
int n;
point s[N];
int top;
signed main() {
ios::sync_with_stdio(false);
cin>>n;
for(int i=1;i<=n;i++) {
p[i].read();
}
q.read();
p[n+1]=p[1];
p[0]=p[n];
oo.x=q.x;
oo.y=1e9;
for(int i=1;i<=n;i++) {
if(p[i].x==q.x && p[i+1].x==q.x) continue;
if(intersect_in(q,oo,p[i],p[i+1])) {
s[++top]=intersection(q,oo,p[i],p[i+1]);
}
}
sort(s+1,s+top+1);
double ans=0;
int flag=0;
for(int i=1;i<=top;i++) {
if(flag) ans+=s[i].y-s[i-1].y;
bool isp = 0;
for(int j=1;j<=n;j++) if(p[j]==s[i]) isp=j;
if(isp==0) {
flag^=1;
}
else {
if((fabs(p[isp+1].x-q.x)<eps) ||
(fabs(p[isp-1].x-q.x)<eps)) {
}
else if((p[isp+1].x-q.x)*(p[isp-1].x-q.x)<-eps) {
flag^=1;
}
}
}
cout<<(int)(floor(ans));
}