1. 程式人生 > >ZOJ1081 Points Within

ZOJ1081 Points Within

在解析幾何中,我們大量的使用列方程求解未知量。但是在計算機計算的時候,解析幾何的演算法因為使用除法過多可能會帶來嚴重的精度誤差,所以簡單來說,計算幾何使用了一些其他的等效的方法來解決這些問題。

這裡先說一個比較基礎的題目,大意為給定一個點數為n的正方形,點按照順序給出,給定m個點,判斷點是否在多邊形內。

我們的判定方法是:過給定的點做與x軸平行的一條射線(方向無所謂),計算其與多邊形的交點個數,如果是奇數個則在多邊形內,否則不在。

但是問題在於可能有一些特殊的情況,比如說交點正好是一條邊的下端點或者上端點。這裡的處理方法是,對於點線上段上的情況直接特判掉,否則如果在上端點相交則視為相交,下端點相交視為不相交。這個是沒有問題的,如果在形外,那麼一個端點會被計算兩次或者不算,結果一樣。如果在形內,那麼對於兩條邊的交點,必然是同時與一上一下端點相交,沒有影響。

至於判斷點線上段上的方法,用到的是向量的內積和外積。而一開始的圖形面積處理用的是向量外積求圖形面積的方法。這些做法以後補上……

所以具體的思路就是,首先構造出一個多邊形,計算一下它的有向面積,如果<0的話就把圖形整體反過來。之後對於給定的每一個點,列舉圖形的所有邊判斷是否與其相交,計算出交點個數之後判定是否在圖形內部即可。

看一下程式碼。

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<cmath>
#include
<set> #include<queue> #define rep(i,a,n) for(int i = a;i <= n;i++) #define per(i,n,a) for(int i = n;i >= a;i--) #define enter putchar('\n') #define fr friend inline using namespace std; typedef long long ll; const int M = 100005; const int INF = 1000000009; const double eps = 1e-6; int read() {
int ans = 0,op = 1; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-') op = -1; ch = getchar(); } while(ch >= '0' && ch <= '9') { ans *= 10; ans += ch - '0'; ch = getchar(); } return ans * op; } struct point { double x,y; point(){} point(double kx,double ky) : x(kx),y(ky) {} fr point operator + (const point &ls,const point &rs)// vector plus { return point(ls.x + rs.x,ls.y + rs.y); } fr point operator - (const point &ls,const point &rs)//vector minus { return point(rs.x - ls.x,rs.y - ls.y); } fr point operator * (const point &p,const double &a)//vector multi { return point(p.x * a,p.y * a); } fr double operator * (const point &ls,const point &rs)//calc area { return ls.x * rs.y - ls.y * rs.x; } fr double dot(const point &ls,const point &rs)//dot product { return ls.x * rs.x + ls.y * rs.y; } }q; inline bool check(const point &u,const point &v,const point &p) { double det = (u - p) * (v - p); if(det != 0) return 0; double D = dot(u - p,v - p); return D <= 0; } struct polygon { int n; point p[M]; void init(int x) { n = x; rep(i,0,n-1) scanf("%lf %lf",&p[i].x,&p[i].y); p[n] = p[0]; if(Area() < 0) reverse(p,p+n); p[n] = p[0]; } inline double Area() const { double res = 0; rep(i,0,n-1) res += p[i] * p[i+1]; return res; } bool inner(const point &q) { int cnt = 0; rep(i,0,n-1) { if(check(p[i],p[i+1],q)) return 1; double d1 = p[i].y - q.y,d2 = p[i+1].y - q.y; double det = (p[i] - q) * (p[i+1] - q); if((det >= 0 && d1 < 0 && d2 >= 0) || (det <= 0 && d1 >= 0 && d2 < 0)) ++cnt; } return cnt & 1; } }P; int t,n,m; int main() { while(++t) { n = read(); if(!n) break; m = read(),P.init(n); if(t != 1) enter; printf("Problem %d:\n",t); while(m--) { scanf("%lf%lf",&q.x,&q.y); if(P.inner(q)) printf("Within\n"); else printf("Outside\n"); } } return 0; }