HRBUST1429—凸多边形
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
【思路分析】(参考http://blog.csdn.net/lttree/article/details/24291719)
该题是判断一个点集是否全部严格在凸多边形之内,这里先介绍一个“二分法”:
其步骤为:
1、选取多边形其中一点作为原点,与其他各点相连并作射线,会得到很多三角形区域
2、判断点集中的一点是否在以多边形原点为端点的最两侧的射线之外,若是,则该点在多边形之外;
3、若该点不满足2中的条件,则继续判断该点是在哪两个相邻的射线区域之内,这里便用到了二分法:
首先定义三个变量,low = 2,high = n - 1,mid = (low + high) / 2。先判断该点是在多边形最中间的射线(p0pmid)的左边还是右边,若在左,令high = mid;
若在右,令low = mid + 1。直到low > high 为止。
4、最后判断该点是否在三角形区域之内,即判断该点与三角形的第三条边和该点的位置关系。设点为a,三角形第三条边两端点分别为pm、p(m + 1),则等价于判断点a在向量pmp(m + 1)的顺时针还是逆时针,若是顺时针,则该点在多边形之内。
这里再自我补充一下判断点和直线的位置关系的方法:
设多边形上两相邻的点分别为p0 、p1,需要判断的点为p2,定义一个叉积函数cross
double cross(Point p0,Point p1,Point p2)
{
return (p1.x - p0.x)*(p2.y - p0.y) -(p1.y - p0.y)*(p2.x - p0.x);
}
若cross(p0,p1,p2)为正,表示点p2在向量p0p1的逆时针方向,若cross(p0,p1,p2)为负,表示点p2在向量p0p1的顺时针方向,若cross(p0,p1,p2)为零,表示p2在向量p0p1之上。
代码如下:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
const int maxn = 100005;
struct Point
{
double x;
double y;
}pointOfPolygon[maxn],pointOfPoint[maxn];
double cross(Point p0,Point p1,Point p2)
{
return (p1.x - p0.x) * (p2.y - p0.y) - (p2.x - p0.x) * (p1.y - p0.y);
}
int main()
{
int n,m;
while(scanf("%d",&n) != EOF)
{
for(int i = 0;i < n;i++)
{
scanf("%lf %lf",&pointOfPolygon[i].x,&pointOfPolygon[i].y);
}
scanf("%d",&m);
for(int i = 0;i < m;i++)
{
scanf("%lf %lf",&pointOfPoint[i].x,&pointOfPoint[i].y);
}
int flag = 0;
for(int i = 0;i < m;i++)
{
if(cross(pointOfPolygon[0],pointOfPolygon[1],pointOfPoint[i]) >= 0 ||
cross(pointOfPolygon[0],pointOfPolygon[n - 1],pointOfPoint[i]) <= 0 )
{//判断该点是否在多边形两最外侧边上及侧边外
flag = 1;
break;
}
int low = 2;
int high = n - 1;
int mid;
while(low < high)//二分确定区域
{
mid = (low + high) >> 1;
if(cross(pointOfPolygon[0],pointOfPolygon[mid],pointOfPoint[i]) > 0)
{
high = mid;
}
else
{
low = mid + 1;
}
}
if(cross(pointOfPolygon[low],pointOfPolygon[low - 1],pointOfPoint[i]) <= 0)
//判断点和三角形第三条边的位置关系
{
flag = 1;
break;
}
}
if(flag == 1)
printf("No\n");
else
printf("Yes\n");
}
return 0;
}