基于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中matplotlib实现最小二乘法拟合的过程详解
Jul 11 Python
PyQt 线程类 QThread使用详解
Jul 16 Python
利用Python写一个爬妹子的爬虫
Jun 08 Python
浅谈Python里面小数点精度的控制
Jul 16 Python
新年快乐! python实现绚烂的烟花绽放效果
Jan 30 Python
10 行Python 代码实现 AI 目标检测技术【推荐】
Jun 14 Python
pycharm设置当前工作目录的操作(working directory)
Feb 14 Python
mac在matplotlib中显示中文的操作方法
Mar 06 Python
Python Http请求json解析库用法解析
Nov 28 Python
python基于pexpect库自动获取日志信息
Feb 01 Python
详解python的内存分配机制
May 10 Python
Python制作动态字符画的源码
Aug 04 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
德生H-501的评价与改造
2021/03/02 无线电
php和数据库结合的一个简单的web实例 代码分析 (php初学者)
2011/07/28 PHP
ThinkPHP验证码使用简明教程
2014/03/05 PHP
PHP中读取照片exif信息的方法
2014/08/20 PHP
PHP+MySQL实现消息队列的方法分析
2018/05/09 PHP
jquery 指南/入门基础
2007/11/30 Javascript
JS 自动安装exe程序
2008/11/30 Javascript
jQuery 表单验证扩展代码(一)
2010/10/11 Javascript
jQuery代码实现发展历程时间轴特效
2015/07/30 Javascript
解决JavaScript数字精度丢失问题的方法
2015/12/03 Javascript
AngularJS 使用$sce控制代码安全检查
2016/01/05 Javascript
jQuery实现表格行和列的动态添加与删除方法【测试可用】
2016/08/01 Javascript
jQuery实现Select左右复制移动内容
2016/08/05 Javascript
Javascript blur与click冲突解决办法
2017/01/09 Javascript
vue文件树组件使用详解
2018/03/29 Javascript
JS实现的汉字与Unicode码相互转化功能分析
2018/05/25 Javascript
基于node.js实现爬虫的讲解
2019/02/18 Javascript
ES7之Async/await的使用详解
2019/03/28 Javascript
javascript实现简易聊天室
2019/07/12 Javascript
基于ssm框架实现layui分页效果
2019/07/27 Javascript
微信小程序JS加载esmap地图的实例详解
2019/09/04 Javascript
如何在vue项目中嵌入jsp页面的方法(2种)
2020/02/06 Javascript
深入浅析golang zap 日志库使用(含文件切割、分级别存储和全局使用等)
2020/02/19 Javascript
vue中实现图片压缩 file文件的方法
2020/05/28 Javascript
Vue切换div显示隐藏,多选,单选代码解析
2020/07/14 Javascript
浅析VUE防抖与节流
2020/11/24 Vue.js
使用python Django做网页
2013/11/04 Python
对Django外键关系的描述
2019/07/26 Python
python实现贪吃蛇游戏源码
2020/03/21 Python
HTML5网页音乐播放器的示例代码
2017/11/09 HTML / CSS
美国滑雪和滑雪板商店:Buckman
2018/03/03 全球购物
Ibatis如何调用存储过程
2015/05/15 面试题
魅力教师事迹材料
2014/01/10 职场文书
文明城市创建标语
2014/06/16 职场文书
客房服务员岗位职责
2015/02/09 职场文书
项目投资意向书范本
2015/05/09 职场文书