基于python 凸包问题的解决

最近在看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 凸包问题的解决就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • Python求凸包及多边形面积教程

    一般有两种算法来计算平面上给定n个点的凸包:Graham扫描法(Graham's scan),时间复杂度为O(nlgn):Jarvis步进法(Jarvis march),时间复杂度为O(nh),其中h为凸包顶点的个数.这两种算法都按逆时针方向输出凸包顶点. Graham扫描法 用一个栈来解决凸包问题,点集Q中每个点都会进栈一次,不符合条件的点会被弹出,算法终止时,栈中的点就是凸包的顶点(逆时针顺序在边界上). 算法步骤如下图: import sys import math import time

  • 基于python 凸包问题的解决

    最近在看python的算法书,之前在年前买的书,一直在工作间隙的时候,学习充电,终于看到这本书,但是确实又有点难,感觉作者写的代码太炫技 了,有时候注释也不怎么能看懂,终于想到一个方法,就是里面说的算法问题,我就百度python解决他,觉得这个挺好. 下面是凸包问题的一个代码. # -*- coding: utf-8 -*- import turtle import random import time f=open('point.txt','w') for i in range(100): x

  • 基于python分布式爬虫并解决假死的问题

    python版本:3.5.4 系统:win10 x64 通过网页下载视频 方法一:使用urllib.retrieve函数 放函数只需要两个参数即可下载相应内容到本地,一个是网址,一个是保存位置 import urllib.request url = 'http://xxx.com/xxx.mp4' file = 'xxx.mp4' urllib.request.retrieve(url, file) 但是博主在使用过程中发现,该函数没有timeout方法.使用时,可能由于网络问题导致假死! 方法

  • 基于python 处理中文路径的终极解决方法

    1 .据说python3就没有这个问题了 2 .u'字符串' 代表是unicode格式的数据,路径最好写成这个格式,别直接跟字符串'字符串'这类数据相加,相加之后type就是str,这样就会存在解码失误的问题. 别直接跟字符串'字符串'这类数据相加 别直接跟字符串'字符串'这类数据相加 别直接跟字符串'字符串'这类数据相加 unicode类型别直接跟字符串'字符串'这类数据相加 说四遍 3 .有些读取的方式偏偏是要读取str类型的路径,不是unicode类型的路径,那么我们把这个str.enco

  • 基于Python安装pyecharts所遇的问题及解决方法

    最近学习到数据可视化内容,老师推荐安装pyecharts,于是pip install 了一下,结果...掉坑了,下面是我的跳坑经验,如果你有类似问题,希望对你有所帮助. 第一个坑: 这个不难理解,缺少pyecharts-jupyter-installer嘛,那就安一个呗.可能有人注意到,我使用的是python2 -m pip ...(这种写法是为了解决python 2和3共存时pip的冲突问题,具体解释在本页最后.) 本以为结束了,却掉进了第二个坑: 看到这个,很明显是安装MarkupSafe时

  • 基于python 等频分箱qcut问题的解决

    在python 较新的版本中,pandas.qcut()这个函数中是有duplicates这个参数的,它能解决在等频分箱中遇到的重复值过多引起报错的问题: 在比较旧版本的python中,提供一下解决办法: import pandas as pd def pct_rank_qcut(series, n): ''' series:要分箱的列 n:箱子数 ''' edages = pd.series([i/n for i in range(n)] # 转换成百分比 func = lambda x: (

  • 基于Python OpenCV和 dlib实现眨眼检测

    目录 了解"眼睛纵横比"(EAR) 使用面部标志和 OpenCV 检测眨眼 眨眼检测结果 总结 今天,我们使用面部标记和 OpenCV 检测视频流中的眨眼次数. 为了构建我们的眨眼检测器,我们将计算一个称为眼睛纵横比 (EAR) 的指标,该指标由 Soukupová 和 Čech 在他们 2016 年的论文<使用面部标记的实时眨眼检测>中介绍. 与计算眨眼的传统图像处理方法不同,传统的图像处理方法通常涉及以下某些组合: 眼睛定位. 阈值以找到眼白. 确定眼睛的"白

  • 基于Python和Scikit-Learn的机器学习探索

    你好,%用户名%! 我叫Alex,我在机器学习和网络图分析(主要是理论)有所涉猎.我同时在为一家俄罗斯移动运营商开发大数据产品.这是我第一次在网上写文章,不喜勿喷. 现在,很多人想开发高效的算法以及参加机器学习的竞赛.所以他们过来问我:"该如何开始?".一段时间以前,我在一个俄罗斯联邦政府的下属机构中领导了媒体和社交网络大数据分析工具的开发.我仍然有一些我团队使用过的文档,我乐意与你们分享.前提是读者已经有很好的数学和机器学习方面的知识(我的团队主要由MIPT(莫斯科物理与技术大学)和

  • 基于Python函数的作用域规则和闭包(详解)

    作用域规则 命名空间是从名称到对象的映射,Python中主要是通过字典实现的,主要有以下几个命名空间: 内置命名空间,包含一些内置函数和内置异常的名称,在Python解释器启动时创建,一直保存到解释器退出.内置命名实际上存在于一个叫__builtins__的模块中,可以通过globals()['__builtins__'].__dict__查看其中的内置函数和内置异常. 全局命名空间,在读入函数所在的模块时创建,通常情况下,模块命名空间也会一直保存到解释器退出.可以通过内置函数globals()

  • 基于python实现在excel中读取与生成随机数写入excel中

    具体要求是:在一份已知的excel表格中读取学生的学号与姓名,再将这些数据放到新的excel表中的第一列与第二列,最后再生成随机数作为学生的考试成绩. 首先要用到的数据库有:xlwt,xlrd,random这三个数据库. 命令如下: import xlwt import xlrd import random 现有一份表格内容如下图: 现在我们需要提取这其中的B1-C14. (提示:在对这份电子表格进行操作的时候,要使用到这个电子表格的地址,即表格的储存位置.) excel=xlrd.open_w

  • 基于python内置函数与匿名函数详解

    内置函数 Built-in Functions abs() dict() help() min() setattr() all() dir() hex() next() slice() any() divmod() id() object() sorted() ascii() enumerate() input() oct() staticmethod() bin() eval() int() open() str() bool() exec() isinstance() pow() super

随机推荐