hrbustoj 1429:凸多邊形(計算幾何,判斷點是否在多邊形內,二分法)


凸多邊形

Time Limit: 2000 MS    Memory Limit: 65536 K

Total Submit: 130(24 users)   Total Accepted: 40(18 users)       Rating:         Special Judge: No

Description

已知一個凸多邊形A(包含n個點,點按照順時針給出),和一個點集B(包含m個點),請判斷這m個點是否都嚴格在凸多邊形A內部。

 

Input

輸入包含多組測試數據。

對於每組測試數據:

第1行,包含一個整數n (3 ≤ n ≤ 105)代表着凸多邊形A的點的數量。

接下來n行每行包含一個坐標(x, y) (-109 ≤ x, y ≤ 109) 表示這個凸多邊形,點按照順時針給出。

第n + 2行,包含一個整數m (3 ≤ m ≤ 105)代表着點集B的點的數量。

接下來m行每行包含一個坐標(x, y) (-109 ≤ x, y ≤ 109) 表示這個點集B。

處理到文件結束

 

Output

對於每組測試數據:

第1行,如果點集B都嚴格在凸多邊形A內,輸出YES,否則輸出NO。

 

Sample Input

4

-10 -10

-10 10

10 10

10 -10

3

0 0

1 1

2 2

4

-10 -10

-10 10

10 10

10 -10

3

100 100

1 1

2 2

 

Sample Output

YES

NO

 

Author

齊達拉圖@HRBUST


 

  計算幾何,判斷點是否在多邊形內(二分法)

  判斷點是否在多邊形內有多種方法,例如:射線法,角度和判斷法,弧長法,二分法。

  射線法是我最開始學的方法,較麻煩;角度和判斷法也叫轉角法,比較方便,但是由於要計算大量的反三角函數,所以速度較慢,容易產生精度誤差。而弧長法的優點恰恰就是精度高,只需作乘法和減法,若對整數坐標則完全沒有精度問題。而且實現簡單,比射線法和轉角法都好寫。二分法速度最快,特別適應於判斷多個點是否在多邊形內的情況。就像這道題。

  其中前三種方法時間復雜度都是O(n),二分法時間復雜度是O(logn)

  這道題的題意是已知構成凸多邊形A的n個點的坐標,和點集B的m個點的坐標,求這B的m個點是否都在凸多邊形A內(嚴格內部,就是點不能在多邊形邊上)。

  思路:用以上前三種方法的任意一種都會超時,時間復雜度為(O(mn)),遂使用二分法,這道題的時間復雜度為(O(mlogn))。

  二分法求多邊形的步驟:

  1、選擇多邊形其中一個點為起點,連接其它點作射線。

  2、判斷給定的點是否在所有射線包圍的區域之內,即判斷給定點是否在最左側射線的左邊,或者在最右側射線的右邊。

  3、如果在射線包圍的區域之內,選擇構成最兩側的射線的點為left和right,則mid = (left+right)/2,連接給頂點和起點作射線,判斷該射線在mid點和起點的哪一邊,不斷循環,如此用二分法最后求出給定點所在的三角形區域,由此確定了除起點外的一條邊。

  4、判斷給定點在這條邊的左方還是右方,由此判斷給定點是否在三角形區域內,也就是是否在多邊形內。

  注意:這道題有個坑,點要求嚴格在多邊形內部,也就是說不能在多邊形的邊上。注意這一點,測試數據控制的很嚴格,WA了好多次才明白過來。

  代碼

 1 #include <stdio.h>
 2 #define eps 1e-10
 3 struct Point{  4     double x,y;  5 };  6 double xmulti(Point p1,Point p2,Point p0)    //求p1p0和p2p0的叉積,如果大於0,則p1在p2的順時針方向
 7 {  8     return (p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y);  9 } 10 Point A[100001],B[100001]; 11 int main() 12 { 13     int i,n,m; 14     while(scanf("%d",&n)!=EOF){ 15         for(i=1;i<=n;i++)    //輸入多邊形的頂點
16             scanf("%lf%lf",&A[i].x,&A[i].y); 17         scanf("%d",&m); 18         for(i=1;i<=m;i++)    //輸入點集
19             scanf("%lf%lf",&B[i].x,&B[i].y); 20         //二分法判斷B上的點是否在原凸多邊形A內,注意在邊上不行
21         for(i=1;i<=m;i++){    //B[i]
22             if(xmulti(B[i],A[2],A[1])<=eps || xmulti(B[i],A[n],A[1])>=-eps)    //在第一個點為起點的扇形之外或在邊上
23                 break; 24             int left=2,right=n; 25             while(right-left!=1){ 26                 int mid = (left+right)/2; 27                 if(xmulti(B[i],A[mid],A[1])>eps) 28                     left = mid; 29                 else 
30                     right = mid; 31  } 32             if(xmulti(B[i],A[right],A[left])<=eps)    //在邊之外或在邊上
33                 break; 34  } 35         if(i>m) 36             printf("YES\n"); 37         else
38             printf("NO\n"); 39  } 40     return 0; 41 }

 

Freecode : www.cnblogs.com/yym2013


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM