射线法
从目标点出发引一条射线,看这条射线和多边形所有边的交点数目:
(1)如果有奇数个交点,则说明在内部;
(2)如果有偶数个交点,则说明在外部.
注:射线可以是任何方向,为了方便代码表示,做水平向右方向射线
特殊情况判定
判断(x ,y)在多边形内
依次遍历讨论两点
point p1;
point p2;
1,y<min(p1.y,p2.y) continue
2 ,y>=max(p1.y,p2.y) continue
这两种情况是点做射线交与p1或p2点,只取一次即可,防止交点多计算一次
3,p1.y==p2.y continue
注意:points内点要按顺序存储
代码实现
bool isInsidePoint(){
int nCross=0;
for(int i=0,j=pts2.size()-1;i<pts2.size();j=i++){
point p1=pts2[i];
point p2=pts2[j];
if(y>max(p1.y,p2.y)) continue;
if(y<=min(p1.y,p2.y)) continue;
if(p1.y==p2.y) continue;
double x2=(y-p1.y)*(p1.x-p2.x)/(p1.y-p2.y)+p1.x;
if(x2>x){
nCross++;
}
}
if(nCross%2==0){
return false;
}else{
return true;
}
}
例题: 并查集+多边形判断
题目:B-大本营_2022河南萌新联赛第(四)场:郑州轻工业大学 (nowcoder.com)
AC代码
#include<bits/stdc++.h>
using namespace std;
const int maxn=2006;
struct point{
double x,y;
double r;
};
vector<point> pts1,pts2;
int p[maxn],v[maxn],st[maxn];
int n,x,y,flag;
void init(){
for(int i=0;i<n;i++){
p[i]=i;
}
}
int finds(int cur){
if(cur==p[cur]){
return cur;
}else{
return p[cur]=finds(p[cur]);
}
}
void merge(int x,int y){
int fx=finds(x);
int fy=finds(y);
if(fx!=fy){
p[fy]=fx;
}
}
bool isInsidePoint(){
int nCross=0;
for(int i=0,j=pts2.size()-1;i<pts2.size();j=i++){
point p1=pts2[i];
point p2=pts2[j];
if(y>max(p1.y,p2.y)) continue;
if(y<=min(p1.y,p2.y)) continue;
if(p1.y==p2.y) continue;
double x2=(y-p1.y)*(p1.x-p2.x)/(p1.y-p2.y)+p1.x;
if(x2>x){
nCross++;
}
}
if(nCross%2==0){
return false;
}else{
return true;
}
}
int main(){
cin>>n>>x>>y;
flag=1;
for(int i=0;i<n;i++){
point temp;
cin>>temp.x>>temp.y>>temp.r;
pts1.push_back(temp);
double s1=(pts1[i].y-y)*(pts1[i].y-y)+(pts1[i].x-x)*(pts1[i].x-x);
double s2=(pts1[i].r)*(pts1[i].r);
if(s1<=s2){
flag=0;
}
}
if(!flag){
cout<<"NO";
return 0;
}
init();
for(int i=0;i<n;i++){
for(int j=i+1;j<n;j++){
double s1=pow((pts1[i].y-pts1[j].y),2)+pow((pts1[i].x-pts1[j].x),2);
double s2=(pts1[i].r+pts1[j].r)*(pts1[i].r+pts1[j].r);
if(s1<=s2){
if(finds(i)!=finds(j)){
merge(i,j);
}else{
st[finds(i)]=1;
}
}
}
}
flag=1;
// for(int i=0;i<n;i++)cout<<st[i]<<" ";
for(int i=0;i<n;i++){
if(st[i]==1){
pts2.clear();
for(int j=0;j<n;j++){
if(finds(j)==i){
pts2.push_back(pts1[j]);
}
}
if(isInsidePoint()){
flag=0;
break;
}
}
}
if(flag){
cout<<"YES";
}else{
cout<<"NO";
}
return 0;
}