Day20200713—点在三角形内
前言
因为各种原因,有一段时间没有开始计划性刷题了。在现在看来,无疑是浪费很多时间。
直到某一天,看到一位大牛每天都有计划性地学习,也看到了其中一道非常有趣的题,想起了高中刷题的日子。
所以从今天开始,开始计划性刷题。
关于标题,是因为这一道算法题的重点在于点在三角形内的运用。
参考
虽然没有使用这个思路,但是非常具有参考价值
题目
描述
示例
解题
关键词与细节
不知道动物园的具体位置,动物园在三角形ABC范围内(包括边界与顶点)
3|OA|+2|OB|+|OC|最小,其中点O为动物园
O、A、B、C均为整点,均在同一个平面
条件
点O在三角形内,且满足3|OA|+2|OB|+|OC|最小
这两个条件只保证了点O的3|OA|+2|OB|+|OC|只有一个最小值
但无法保证只有一个点O,因为可能存在多个点O都具有相同的3|OA|+2|OB|+|OC|最小值。
解题思路
条件1
以三角形的三个顶点获取一个正方形区域即可,如下:
则点O即在正方形区域内,由于O、A、B、C均为整点,数量是有限的。
通过条件1获取点O集合
条件2:点O在三角形区域内
将条件1获取的集合进行筛选,需要满足条件:点O在三角形内
1. 点 O , A , B , C 的 坐 标 分 别 为 : ( x 0 , y 0 ) , ( x 1 , y 1 ) , ( x 2 , y 2 ) , ( x 3 , y 3 ) − − − − − 2. 如 果 点 O 在 三 角 形 A B C 内 的 话 , 会 满 足 以 下 条 件 : S A B O ∗ O C → + S A C O ∗ O B → + S B C O ∗ O A → = 0 → − − − − − 3. 已 知 三 角 形 顶 点 坐 标 , 可 以 通 过 以 下 公 式 计 算 : S A B C = ( 1 / 2 ) ∗ ( x 1 y 2 + x 2 y 3 + x 3 y 1 − x 1 y 3 − x 2 y 1 − x 3 y 2 ) 1.点O,A,B,C的坐标分别为:(x0,y0),(x1,y1),(x2,y2),(x3,y3)\\ -----\\ 2.如果点O在三角形ABC内的话,会满足以下条件:\\ S_{ABO}*\overrightarrow{OC}+S_{ACO}*\overrightarrow{OB}+S_{BCO}*\overrightarrow{OA}=\overrightarrow{0}\\ -----\\ 3.已知三角形顶点坐标,可以通过以下公式计算:\\ S_{ABC}=(1/2)*(x1y2+x2y3+x3y1-x1y3-x2y1-x3y2) 1.点O,A,B,C的坐标分别为:(x0,y0),(x1,y1),(x2,y2),(x3,y3)−−−−−2.如果点O在三角形ABC内的话,会满足以下条件:SABO∗OC+SACO∗OB+SBCO∗OA=0−−−−−3.已知三角形顶点坐标,可以通过以下公式计算:SABC=(1/2)∗(x1y2+x2y3+x3y1−x1y3−x2y1−x3y2)
条件3:取得最小值
有两个思路
思路1:使用一个标记对象,当出现更小的值时,将产生该值的对象赋予给标记对象
思路2:
使用两个集合,集合1存储所有所有满足条件1和条件2的点O
集合2存储对应产生的3|OA|+2|OB|+|OC|值。获得集合2中最小值的索引,返回集合1对应索引上的值即可
思路1和思路2产生的结果不同,当存在多个点O时,思路2,将返回多个点O,但思路1只能返回一个点O
由于示例返回一个即可,所以使用思路1即可
算法实现
程序代码
import math
class Node(object):
def __init__(self,x,y):
self.x = x
self.y = y
class parrot(object):
def __init__(self,a,b,c):
""" a,b,c is a Node """
self.a = a
self.b = b
self.c = c
self.list_node = [self.a,self.b,self.c]
def getDist(self,a,b):
return math.sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y))
def getSum(self,node_o):
return 3*self.getDist(node_o,self.a)+\
2*self.getDist(node_o,self.b)+self.getDist(node_o,self.c)
def areaoftriangle(self,node_a,node_b,node_c):
#S=(1/2)*(x1y2+x2y3+x3y1-x1y3-x2y1-x3y2)
"""
node_a.x node_b.x node_c.x
node_a.y node_b.y node_c.y
"""
area = (1/2)*abs(
node_a.x*node_b.y+node_b.x*node_c.y+node_c.x*node_a.y
\
-node_a.x*node_c.y-node_b.x*node_a.y-node_c.x*node_b.y
)
return area
def buildvector(self,node_1,node_2):
return Node(node_2.x-node_1.x,node_2.y-node_1.y)
def vectorofmultiply(self,k,vector):
return Node(k*vector.x,k*vector.y)
def vectorofsum(self,vector1,vector2,vector3):
return Node(
vector1.x+vector2.x+vector3.x,vector1.y+vector2.y+vector3.y
)
def check_in_out(self,node_o:Node):
# Node
vector_oa = self.buildvector(self.a,node_o)
vector_ob = self.buildvector(self.b,node_o)
vector_oc = self.buildvector(self.c,node_o)
# area
area_aco = self.areaoftriangle(self.a,self.c,node_o)
area_bco = self.areaoftriangle(self.b,self.c,node_o)
area_abo = self.areaoftriangle(self.a,self.b,node_o)
# sum = Sbco*Vector(oa)+Saco*Vector(ob)+Sabo*Vector(oc)=Vector(0,0)
sum = self.vectorofsum(
self.vectorofmultiply(area_bco,vector_oa),
self.vectorofmultiply(area_aco,vector_ob),
self.vectorofmultiply(area_abo,vector_oc)
)
if sum.x == 0 and sum.y == 0:
return True
return False
def run(self):
list_x,list_y = [],[]
for i in self.list_node:
list_x.append(i.x)
list_y.append(i.y)
max_x,min_x = max(list_x),min(list_x)
max_y,min_y = max(list_y),min(list_y)
result,sumList = [],[]
minSum = float('inf')
flag = None
for i in range(min_x,max_x+1):
for j in range(min_y,max_y+1):
if self.check_in_out(Node(i,j)):
if minSum > self.getSum(Node(i,j)):
minSum = self.getSum(Node(i,j))
flag = Node(i,j)
return flag
if __name__ == "__main__":
a = Node(0,1)
b = Node(0,0)
c = Node(2,0)
o = Node(1,0)
parrotObj = parrot(a,b,c)
flag = parrotObj.run()
print(flag.x,flag.y)
运行截图
思考
这一道题,更加侧重于数学思维,例如三角形面积公式,点在三角形内等等知识,都是一个很好的切入点。
三角形面积公式拓展下去,就有很多知识点,例如海伦公式等等。
而点在三角形内,则有重心法等等。
而大多数题都是侧重于经典数据结构和经典的算法。这也验证了当初那句
算法+数据结构=程序
算法和数据结构都同等重要。
后续
将会在这段时间内抽出时间,补充关于点在三角形内的更多方法和证明。