基于python 凸包问题的解决


Posted in Python onApril 16, 2020

最近在看python的算法书,之前在年前买的书,一直在工作间隙的时候,学习充电,终于看到这本书,但是确实又有点难,感觉作者写的代码太炫技 了,有时候注释也不怎么能看懂,终于想到一个方法,就是里面说的算法问题,我就百度python解决他,觉得这个挺好。

下面是凸包问题的一个代码。

# -*- coding: utf-8 -*-
import turtle
import random
import time
f=open('point.txt','w')
for i in range(100):
 x=random.randrange(-250,250,10)
 y=random.randrange(-200,200,10)
 f.write(str(x)+','+str(y)+'\n')
f.close()
point=[]
 
f=open('point.txt')
for i in f:
 try:
  temp=i.split(',')
  x=float(temp[0]); y=float(temp[1])
  point.append((x,y))
 except :
  print 'a err'
f.close()
 
point=list(set(point))#去除重复的点
 
n=0
for i in range(len(point)):
 if point[n][1]>point[i][1]:
  n=i
 
p0=point[n]
point.pop(n)
def compare(a,b):
 x=[a[0]-p0[0],a[1]-p0[1]]
 y=[b[0]-p0[0],b[1]-p0[1]]
 dx=(x[0]**2+x[1]**2)**0.5
 dy=(y[0]**2+y[1]**2)**0.5
 cosa=x[0]/dx
 cosb=y[0]/dy
 if cosa < cosb:
  return 1
 elif cosa > cosb:
  return -1
 else:
  if dx<dy:
   return -1
  elif dx>dy:
   return 1
  else:
   return 0
 
point.sort(compare)
point.insert(0,p0)
ep=point[:]#复制元素,操作ep不会对point产生影响
tag=0
while tag==0:
 tag=1
 l=len(ep)
 for i in range(l):
  i1,i2,i3=(i,(i+1)%l,(i+2)%l)
  x,y,z=(ep[i1],ep[i2],ep[i3])
  a1,a2=((y[0]-x[0],y[1]-x[1]),(z[0]-y[0],z[1]-y[1]))
  if a1[0]*a2[1]-a1[1]*a2[0] < 0:
   tag=0
   ep.pop(i2)
   break
  elif a1[0]*a2[1]-a1[1]*a2[0]==0 and a1[0]*a2[0]<0:
   #==0应改写,360度的情况
   tag=0
   ep.pop(i2)
   break
 
 
def drawpoint(point,color,line):
 p=turtle.getturtle()
 p.hideturtle()
 turtle.delay(1)
 if(line=='p'):
  p.speed(0)
  for i in point:
   p.pu()
   p.color(color)
   p.goto(i)
   p.pd()
   p.dot()
 elif(line=='l'):
  p.pu()
  p.speed(1)
  for i in point:
   p.color(color)
   p.goto(i)
   p.pd()
   p.dot()
  p.goto(point[0])
 
drawpoint(point,'black','p')
drawpoint(ep,'red','l')
time.sleep(1)

补充知识:凸包问题的蛮力算法及python实现

蛮力法的基本思想是先用排除法确定凸包的顶点,然后按逆时针顺序输出这些顶点。在判断点P是不是凸包上的顶点时,有如下性质:

给定平面点集S,P,Pi,Pj,Pk是S中四个不同的点,如果P位于Pi,Pj,Pk组成的三角形内部或边界上,则P不是S的凸包顶点。

那么如何判断点P在三角形内部或边界上?给定平面两点AB,直线方程g(A,B,P)=0时,P位于直线上,g(A,B,P)>0和g(A,B,P)<0时,P分别位于直线的两侧。

判断点P在三角形内部或边界上只需依次检查P和三角形的每个顶点是否位于三角形另外两个顶点确定的直线的同一侧,即判断:

t1=g(pj,pk,p)*g(pj,pk,pi)>=0 ,
t2=g(pi,pk,p)*g(pi,pk,pj)>=0,
t3=g(pj,pi,p)*g(pj,pi,pk)>=0

是否同时成立

凸包问题的蛮力算法伪代码如下:

BruteForce(S):

输入:平面n个点的集合S

输出:按逆时针顺序输出S的凸包的所有顶点

If n=3  Then 以逆时针顺序输出S的顶点,算法结束 找到S中纵坐标最小的点P,该点一定位于凸包上

For S中任意三点Pi,Pj,Pk Do If Pi,Pj,Pk 一点位于其他两点与P构成的三角形内 Then 删除该点

找出S中横坐标最小的点A和横坐标最小的点B

将S划分问直线AB上方点集SU,直线AB下方点集SL,A,B两点属于SL

将SL按横坐标递增排序,SU按横坐标递减排序顺序输出SL,SU

首先随机生成点集S

import random
import itertools

def generate_num(n):
  random_list = list(itertools.product(range(1, 100), range(1, 100)))
  lists=random.sample(random_list, n)
  return lists

判断点P在三角形内部或边界上,即判断点P是否在凸包上

在具体的判断过程中,尤其时坐标点比较密集的情况下,还有有三种比较特殊的情况

组成直线的两点垂直于x轴

除点P外其余三点在一条直线上时,不应删除点P,因为此时点P可能时凸包上的点

除点P外其余三点在一条直线上且垂直于x轴时,不应删除点P,因为此时点P可能时凸包上的点

#判断pi是否位于pj,pk,p0组成三角形内,返回t1,t2,t3三个变量
def isin(pi,pj,pk,p0):
 x1 = float(p0[0])
 x2 = float(pj[0])
 x3 = float(pi[0])
 x4 = float(pk[0])
 y1 = float(p0[1])
 y2 = float(pj[1])
 y3 = float(pi[1])
 y4 = float(pk[1])

 k_j0=0
 b_j0=0
 k_k0=0
 b_k0=0
 k_jk=0
 b_jk=0
 perpendicular1=False
 perpendicular2 = False
 perpendicular3 = False
 #pj,p0组成的直线,看pi,pk是否位于直线同一侧

 if x2 - x1 == 0:
 #pj,p0组成直线垂直于X轴时
  t1=(x3-x2)*(x4-x2)
  perpendicular1=True
 else:
  k_j0 = (y2 - y1) / (x2 - x1)
  b_j0 = y1 - k_j0 * x1
  t1 = (k_j0 * x3 - y3 + b_j0) * (k_j0 * x4 - y4 + b_j0)

 #pk,p0组成的直线,看pi,pj是否位于直线同一侧

 if x4 - x1 == 0:
 #pk,p0组成直线垂直于X轴时
  t2=(x3-x1)*(x2-x1)
  perpendicular2=True
 else:
  k_k0 = (y4 - y1) / (x4 - x1)
  b_k0 = y1 - k_k0 * x1
  t2 = (k_k0 * x3 - y3 + b_k0) * (k_k0 * x2 - y2 + b_k0)

 # pj,pk组成的直线,看pi,p0是否位于直线同一侧

 if x4 - x2 == 0:
 # pj,pk组成直线垂直于X轴时
  t3=(x3-x2)*(x1-x2)
  perpendicular3 = True
 else:
  k_jk = (y4 - y2) / (x4 - x2)
  b_jk = y2 - k_jk * x2
  t3 = (k_jk * x3 - y3 + b_jk) * (k_jk * x1 - y1 + b_jk)
 #如果pk,p0,pj,三点位于同一直线时,不能将点删除
 if (k_j0 * x4 - y4 + b_j0)==0 and (k_k0 * x2 - y2 + b_k0)==0 and (k_jk * x1 - y1 + b_jk)==0 :
   t1=-1
 #如果pk,p0,pj,三点位于同一直线时且垂直于X轴,不能将点删除
 if perpendicular1 and perpendicular2 and perpendicular3:
   t1=-1

 return t1,t2,t3

接下来是实现算法主要部分,用来找出凸包上的点

import isintriangle

def force(lis,n):
 #集合S中点个数为3时,集合本身即为凸包集
 if n==3:
  return lis
 else:
  #集合按纵坐标排序,找出y最小的点p0
  lis.sort(key=lambda x: x[1])
  p0=lis[0]
  #除去p0的其余点集合lis_brute
  lis_brute=lis[1:]
  #temp是用来存放集合需要删除的点在lis_brute内的索引,四个点中如果有一个点在其余三个点组成的三角形内部,则该点一定不是凸包上的点
  temp=[]
  #三重循环找到所有这样在三角形内的点
  for i in range(len(lis_brute)-2):
   pi=lis_brute[i]
   #如果索引i已经在temp中,即pi一定不是凸包上的点,跳过这次循环
   if i in temp:
    continue
   for j in range(i+1,len(lis_brute) - 1):
    pj=lis_brute[j]
    #如果索引j已经在temp中,即pj一定不是凸包上的点,跳过这次循环
    if j in temp:
     continue
    for k in range(j + 1, len(lis_brute)):
     pk=lis_brute[k]

     #如果索引k已经在temp中,即pk一定不是凸包上的点,跳过这次循环
     if k in temp:
      continue
     #判断pi是否在pj,pk,p0构成的三角形内
     (it1,it2,it3)=isintriangle.isin(pi,pj,pk,p0)
     if it1>=0 and it2>=0 and it3>=0:
      if i not in temp:
       temp.append(i) 
     # 判断pj是否在pi,pk,p0构成的三角形内
     (jt1,jt2,jt3)=isintriangle.isin(pj,pi,pk,p0)
     if jt1>=0 and jt2>=0 and jt3>=0:

      if j not in temp:
       temp.append(j)

     # 判断pk是否在pj,pi,p0构成的三角形内
     (kt1, kt2, kt3) = isintriangle.isin(pk, pi, pj, p0)
     if kt1 >= 0 and kt2 >= 0 and kt3 >= 0:

      if k not in temp:
       temp.append(k)
  #listlast是最终选出的凸包集合
  lislast=[]
  for coor in lis_brute:
   loc = [i for i, x in enumerate(lis_brute) if x == coor]
   for x in loc:
    ploc = x
   if ploc not in temp:
    lislast.append(coor)
  #将p0加入凸包集合
  lislast.append(p0)
  return lislast

最后将凸包集合输出就不多说了,按照伪码上实现就可以,凸包蛮力算法在点集大小为1000时结果

基于python 凸包问题的解决

以上这篇基于python 凸包问题的解决就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Python 相关文章推荐
python实现代理服务功能实例
Nov 15 Python
在Python中编写数据库模块的教程
Apr 29 Python
python遍历目录的方法小结
Apr 28 Python
Python实现登录接口的示例代码
Jul 21 Python
Python实现的三层BP神经网络算法示例
Feb 07 Python
python装饰器深入学习
Apr 06 Python
解决新django中的path不能使用正则表达式的问题
Dec 18 Python
将Pytorch模型从CPU转换成GPU的实现方法
Aug 19 Python
Django的CVB实例详解
Feb 10 Python
使用OpenCV实现人脸图像卡通化的示例代码
Jan 15 Python
matplotlib源码解析标题实现(窗口标题,标题,子图标题不同之间的差异)
Feb 22 Python
python urllib库的使用详解
Apr 13 Python
python实现交并比IOU教程
Apr 16 #Python
python 弧度与角度互转实例
Apr 15 #Python
使用Python三角函数公式计算三角形的夹角案例
Apr 15 #Python
Python selenium自动化测试模型图解
Apr 15 #Python
python简单实现最大似然估计&amp;scipy库的使用详解
Apr 15 #Python
Python unittest单元测试框架及断言方法
Apr 15 #Python
python 连续不等式语法糖实例
Apr 15 #Python
You might like
使用PHP遍历文件目录与清除目录中文件的实现详解
2013/06/24 PHP
ThinkPHP 3.2 数据分页代码分享
2014/10/14 PHP
PHP实现的文件操作类及文件下载功能示例
2016/12/24 PHP
php封装一个异常的处理类
2017/06/08 PHP
用JQuery 实现的自定义对话框
2007/03/24 Javascript
3Z版基于jquery的图片复选框(asp.net+jquery)
2010/04/12 Javascript
用js实现in_array的方法
2013/11/05 Javascript
JavaScript中自定义事件用法分析
2014/12/23 Javascript
基于ajax实现文件上传并显示进度条
2015/08/03 Javascript
jQuery动态修改字体大小的方法【测试可用】
2016/09/09 Javascript
Vue的百度地图插件尝试使用
2017/09/06 Javascript
vue + element-ui实现简洁的导入导出功能
2017/12/22 Javascript
M2实现Nodejs项目自动部署的方法步骤
2019/05/05 NodeJs
jQuery位置选择器用法实例分析
2019/06/28 jQuery
vue分页器组件编写方法详解
2019/06/28 Javascript
JavaScript实现省份城市的三级联动
2020/02/11 Javascript
python自动化工具日志查询分析脚本代码实现
2013/11/26 Python
Python科学计算包numpy用法实例详解
2018/02/08 Python
python如何通过twisted实现数据库异步插入
2018/03/20 Python
pandas中去除指定字符的实例
2018/05/18 Python
Tensorflow中的placeholder和feed_dict的使用
2018/07/09 Python
python提取包含关键字的整行数据方法
2018/12/11 Python
Windows下Anaconda安装、换源与更新的方法
2020/04/17 Python
Python实现一个简单的毕业生信息管理系统的示例代码
2020/06/08 Python
python3 kubernetes api的使用示例
2021/01/12 Python
html5+css3实现一款注册表单实例
2013/04/17 HTML / CSS
比利时家具购买网站:Home24
2019/01/03 全球购物
牛津在线药房:Oxford Online Pharmacy
2020/11/16 全球购物
linux面试题参考答案(6)
2016/06/23 面试题
回门宴新郎答谢词
2014/01/12 职场文书
《学会合作》教学反思
2014/04/12 职场文书
关于教师节的广播稿
2014/09/10 职场文书
学校运动会报道稿
2014/09/23 职场文书
购房委托书
2014/10/15 职场文书
行政主管岗位职责
2015/02/03 职场文书
公证书
2019/04/17 职场文书