基于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基础教程之元组操作使用详解
Mar 25 Python
Python和GO语言实现的消息摘要算法示例
Mar 10 Python
Python pygorithm模块用法示例【常见算法测试】
Aug 16 Python
Python实现的银行系统模拟程序完整案例
Apr 12 Python
python3实现斐波那契数列(4种方法)
Jul 15 Python
Python Web版语音合成实例详解
Jul 16 Python
基于pytorch的保存和加载模型参数的方法
Aug 17 Python
Python传递参数的多种方式(小结)
Sep 18 Python
numpy.transpose()实现数组的转置例子
Dec 02 Python
Python 窗体(tkinter)下拉列表框(Combobox)实例
Mar 04 Python
python中sklearn的pipeline模块实例详解
May 21 Python
Django celery异步任务实现代码示例
Nov 26 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 数组随机取值的简单实例
2016/05/23 PHP
PHP中$GLOBALS['HTTP_RAW_POST_DATA']和$_POST的区别分析
2017/07/03 PHP
PHP cookie与session会话基本用法实例分析
2019/11/18 PHP
jquery.AutoComplete.js中文修正版(支持firefox)
2010/04/09 Javascript
jcarousellite.js 基于Jquery的图片无缝滚动插件
2010/12/30 Javascript
Extjs优化(一)删除冗余代码提高运行速度
2013/04/15 Javascript
javascript实现简单的Map示例介绍
2013/12/23 Javascript
jQuery(js)获取文字宽度(显示长度)示例代码
2013/12/31 Javascript
JavaScript中九种常用排序算法
2014/09/02 Javascript
jquery实现的缩略图预览滑块实例
2015/06/25 Javascript
设计模式中的组合模式在JavaScript程序构建中的使用
2016/05/18 Javascript
js不间断滚动的简单实现
2016/06/03 Javascript
javascript鼠标滑过显示二级菜单特效
2020/11/18 Javascript
js改变透明度实现轮播图的算法
2020/08/24 Javascript
JQuery.dataTables表格插件添加跳转到指定页
2017/06/09 jQuery
Vue shopCart 组件开发详解
2018/01/26 Javascript
Python os模块学习笔记
2015/06/21 Python
python对html过滤处理的方法
2018/10/21 Python
python 通过麦克风录音 生成wav文件的方法
2019/01/09 Python
python3.6使用tkinter实现弹跳小球游戏
2019/05/09 Python
PyQt5通信机制 信号与槽详解
2019/08/07 Python
python实现飞机大战小游戏
2019/11/08 Python
Python测试Kafka集群(pykafka)实例
2019/12/23 Python
Pytorch之contiguous的用法
2019/12/31 Python
Pycharm最常用的快捷键及使用技巧
2020/03/05 Python
python+requests接口压力测试500次,查看响应时间的实例
2020/04/30 Python
eBay奥地利站:eBay.at
2019/07/24 全球购物
国际商务专业学生个人的自我评价
2013/09/28 职场文书
公司同意接收函
2014/01/13 职场文书
体现团队精神的口号
2014/06/06 职场文书
车辆年审委托书范本
2014/09/18 职场文书
初婚初育证明范本
2014/11/24 职场文书
升职自荐信范文
2015/03/27 职场文书
2019年妇科护士的自我鉴定(3篇)
2019/09/26 职场文书
Nginx配置文件详解以及优化建议指南
2021/09/15 Servers
在ubuntu下安装go开发环境的全过程
2022/08/05 Golang