先百度一下凹多边形的定义:把一个各边不自交的多边形任意一边向两方无限延长成为一直线,如果多边形的所有边中只要有一条边向两方无限延长成为一直线时,其他各边不在此直线的同旁,那么这个多边形就叫做凹多边形。凹多边形有一个或多个内角大于180度。
问:给出一个多边形的顶点集合,顶点与边的关系已知,如何判断这个多边形是否是一个凹多边形呢?
如顶点集 ((0,0),(0,5),(5,5),(4,3),(5,0)) 围成了一个5变形,如何判断这个5变形是否是凹多边形?
我给出的解法是:根据凹多边形的定义,如果将所有的边都无限延长成一条直线,必有一条直线会将这个图形切割成两半;而如果这个图形凸多边形则不会有这种情况。因此,我的解法需要从某一个顶点开始,顺时针(或逆时针)遍历完所有的边,每遍历一条边,都判断所有的顶点是否全部在这条直线的一侧,如果不是,说明这个图形是凹多边形。很明显,这个解法的算法复杂度是O(N^2),因为遍历所有顶点的开销需要 n,而每遍历一个顶点都需要比较其它n个顶点,合起来开销就是 n*n=n^2.
我这个这个解法还涉及一个高中的数学知识:如何判断做标为 (x,y)的点在直线的哪一侧?
设直线是由其上两点(x1,y1)(x2,y2)确定的,直线方向是由(x1,y1)到(x2,y2)的方向。这时若直线方程记为Ax+By+C=0
则有:
A=y2-y1; B=x1-x2; C=x2*y1-x1*y2;
这时可以计算D:
D=A*xp+B*yp+C
若D<0,则点(xp,yp)在直线的左侧;若D>0,则点在直线的右侧;D=0点在直线上。
小明童鞋的解法效率很高,证明方法也很独特,特将其解法抄录下来:
定义:按照顶点的顺序,当我们从上一个顶点沿着边走向当前顶点时,若下个顶点在我们的左边(逆时针方向),我们称下个顶点为正顶点。
定理:每个顶点都是正顶点的多边形为凸多边形。
polygon=((0,0),(0,5),(5,5),(4,3),(5,0))
def IsConVex(polygon):
r=len(polygon)
for i in xrange(r):
#向量(下一个顶点与当前顶点,用来构建直线方程)
x,y=polygon[(i+1)%r][0] - polygon[i%r][0], polygon[(i+1)%r][1] - polygon[(i%r)][1]
x1,y1=polygon[(i+1)%r] #下一个顶点
x2,y2=polugon[(i-1+r)%r] #上一个顶点
if (y*x2 + x*y1 - y*x1) > y2*x: #若下一个顶点不是正顶点
return False
return True
这个方法只需要遍历一次所有的顶点,因此复杂度是 n 。
转自:http://www.caxtu.com/thread-1080-1-1.html