射線法
這是一個大佬看了都說簡單的算法。。。。(甚至覺得沒有掌握的必要)
QAQ
這個算法是用來判斷一個點是否在一個多邊形以內。很簡單 將這個點沿着x軸的正方向作射線。如果穿過的邊數為基數,那么這個點在多邊形內;反之不在。
由於有可能出現經過兩條邊的相鄰的點,而被重復計算的情況。我們只需要采用上加下不加策略,即如果射線經過了這條邊的上頂點,則cnt++,如果經過下頂點,則不變。經過這條邊上除了上頂點和下頂點的地方,cnt++。正確性顯然。
另外因為我們需要將每條邊都遍歷完。而我們只向 x的正方向做了射線,那么完全在詢問點的左邊的邊不能計算。可是每條邊都遍歷,難道不會計算嗎?
不!不會計算。自己去手動模擬一下條件,當其在左邊的時候,康康是否被重復計算了呢(沒有)
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int maxn=1e6;
int n,m;
struct point{
double x,y;
point(){x=0,y=0;}
point(double a,double b){x=a,y=b;}
point operator+(const point &b)const{return point(x+b.x,y+b.y);}
point operator-(const point &b)const{return point(x-b.x,y-b.y);}
point operator*(const double &b)const{return point(x*b,y*b);}
double operator*(const point &b)const{return x*b.y-y*b.x;}
double dot()const{return x*x+y*y;}
double dot(const point &b)const{return x*b.x+y*b.y;}
};
point p[maxn];
inline double cross(const point &a,const point &b){return a.x*b.y-a.y*b.x;}
inline double d(const point &a,const point &b){return sqrt((a-b).dot());}
inline bool check(const point &a,const point &b,const point &c){
if(fabs(d(a,c)+d(b,c)-d(a,b))==0) return true;
return false;
}
inline double area(){
double sum=0;
for(int i=0;i<n;i++) sum+=cross(p[i],p[i+1]);
return sum;
}
void init(){
for(int i=0;i<n;i++){
scanf("%lf %lf",&p[i].x,&p[i].y);
}
p[n]=p[0];
// if(area()<0) reverse(p,p+n);
p[n]=p[0];
}
int main(){
for(int test=1;;test++){
scanf("%d",&n);if(n==0) break;
// scanf("%d",&m);
init();
// if(test!=1) printf("\n");
// printf("Problem %d:\n",test);
// while(m--){
int cnt=0;
point q;
scanf("%lf %lf",&q.x,&q.y);
for(int i=1;i<=n;i++){
if(check(p[i-1],p[i],q)){printf("T\n");break;}
double height1=p[i-1].y-q.y,height2=p[i].y-q.y;
double cro=cross((p[i-1]-q),(p[i]-q));
if((cro>=0 && height1<0 && height2>=0) || (cro<=0 && height1>=0 && height2<0)) cnt++;
}
if(cnt&1) printf("T\n");
else printf("F\n");
// }
}
return 0;
}