Excel精英培训网

 找回密码
 注册
数据透视表40+个常用小技巧,让你一次学会!
查看: 1994|回复: 8

[VBA] 用VBA解欧拉计划题目(102)--包含原点的三角形

[复制链接]
发表于 2017-12-28 20:35 | 显示全部楼层 |阅读模式
包含原点的三角形
从笛卡尔平面中随机选择三个不同的点,其坐标均满足-1000 ≤ x, y ≤ 1000,这三个点构成一个三角形。
考虑下面两个三角形:
A(-340,495), B(-153,-910), C(835,-947)X(-175,41), Y(-421,-714), Z(574,-645)
可以验证三角形ABC包含原点,而三角形XYZ不包含原点。
在27K的文本文件triangles.txt中包含了一千个“随机”三角形的坐标,找出其中包含原点在其内部的三角形的数量。
注意:文件中的前两个三角形就是上述样例。

excel精英培训的微信平台,每天都会发送excel学习教程和资料。扫一扫明天就可以收到新教程
 楼主| 发表于 2017-12-28 20:36 | 显示全部楼层
提示:如果点P在三角形内,那么从A->B->C->A走一圈,点P始终在自己某一侧

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
回复

使用道具 举报

发表于 2017-12-29 22:25 | 显示全部楼层
  1. Sub test() 'by kagawa 2017/12/29
  2.     '包含原点的三角形=228个

  3.     Open ActiveWorkbook.Path & "\p102_triangles.txt" For Input As #1
  4.     a = Split(Input(LOF(1), #1), vbLf)  '提取全部字符串并按[换行]拆分为数组
  5.     Close #1
  6.    
  7.     m = UBound(a) - 1: n = 6
  8.     ReDim ar(m, n + 4)
  9.     For i = 0 To m
  10.         For j = 0 To n - 1
  11.             tr = Split(a(i), ",") '按行拆分数组
  12.             ar(i, j + 1) = Val(tr(j)) '写入x,y坐标
  13.         Next
  14.         For j = 0 To 3
  15.             ar(i, n + j + 1) = ar(i, j + 1) '重复1,2方便循环计算
  16.         Next
  17.     Next
  18.         
  19.     For i = 0 To m
  20.         For j = 1 To 5 Step 2 '循环计算点1,点2连线的斜率k和截距b 以及过点3斜率k时的截距b1
  21.             If ar(i, j) = ar(i, j + 2) Then 'x=b垂直线时
  22.                 b = ar(i, j) '取点1点2的x值b
  23.                 b1 = ar(i, j + 4) '取点3的x值b1
  24.             Else
  25.                 k = (ar(i, j + 1) - ar(i, j + 3)) / (ar(i, j) - ar(i, j + 2)) '计算斜率k
  26.                 b = ar(i, j + 1) - k * ar(i, j) '截距b
  27.                 b1 = ar(i, j + 5) - k * ar(i, j + 4) '斜率k的直线过点3时的截距b1
  28.             End If
  29.             If b * b1 > 0 Then Exit For '截距必须符号相反 否则点3和坐标轴原点就会在直线两端
  30.         Next
  31.         If j = 7 Then ar(i, 0) = 1: cnt = cnt + 1
  32.     Next
  33.     Debug.Print cnt
  34.    
  35.     [a5].Resize(m + 1, n + 1) = ar
  36.     MsgBox cnt
  37. End Sub
复制代码
回复

使用道具 举报

发表于 2017-12-29 22:54 | 显示全部楼层
附件中还有一些提取文本文件的语句。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
回复

使用道具 举报

发表于 2017-12-30 09:44 | 显示全部楼层
索性写成自定义函数了,可以判断任意坐标点,是否包含在3点坐标组成的三角形之内。

  1. Function IsInTriAng(Rng) As Boolean
  2.     If Chk(Rng(1), Rng(2), Rng(3), Rng(4), Rng(5), Rng(6), Rng(7), Rng(8)) Then
  3.         If Chk(Rng(1), Rng(2), Rng(5), Rng(6), Rng(7), Rng(8), Rng(3), Rng(4)) Then
  4.             If Chk(Rng(1), Rng(2), Rng(7), Rng(8), Rng(3), Rng(4), Rng(5), Rng(6)) Then
  5.                 IsInTriAng = True
  6.             End If
  7.         End If
  8.     End If
  9. End Function
  10. Function IsInTriAngle(x, y, x1, y1, x2, y2, x3, y3) As Boolean
  11.     If Chk(x, y, x1, y1, x2, y2, x3, y3) Then
  12.         If Chk(x, y, x2, y2, x3, y3, x1, y1) Then
  13.             If Chk(x, y, x3, y3, x1, y1, x2, y2) Then
  14.                 IsInTriAngle = True
  15.             End If
  16.         End If
  17.     End If
  18. End Function
  19. Function Chk(x, y, x1, y1, x2, y2, x3, y3) As Boolean
  20.     If x1 = x2 Then
  21.         Chk = (x1 - x) * (x3 - x) <= 0
  22.     Else
  23.         k = (y1 - y2) / (x1 - x2)
  24.         b1 = y1 - k * x1: b = y - k * x: b2 = y3 - k * x3
  25.         Chk = (b1 - b) * (b2 - b) <= 0
  26.     End If
  27. End Function
复制代码
回复

使用道具 举报

发表于 2017-12-30 09:48 | 显示全部楼层
第一个只用一个参数,把数据按照x, y, x1, y1, x2, y2, x3, y3的格式输入1行8列区域后引用。
或者,按照:
x, y;
x1, y1;
x2, y2;
x3, y3
这样4行2列的格式输入区域后引用。

第2个函数,则需要逐个输入8个坐标参数。
显然第1种方式非常方便,但对格式要求是固定的。

而第二种方式可以任意使用,尤其是在VBA中使用时,可能更方便、准确。
回复

使用道具 举报

发表于 2017-12-30 13:17 | 显示全部楼层
又找了一种计算点线之间向量关系类型,然后比较是否都为相同类型(含重叠)的快速计算方法。

效率更高啊,且可以扩展为判断点是否包含在任意多边形内。

  1. Function PLineRel(x1, y1, x2, y2, x, y) '点线向量关系类型的计算
  2.     r = x1 * (y2 - y) + x2 * (y - y1) + x * (y1 - y2)
  3.     If r < 0 Then PLineRel = "<" Else If r > 0 Then PLineRel = ">" Else PLineRel = "=" '重叠
  4. End Function
  5. Sub test2() 'by kagawa 2017/12/30
  6.     Open ActiveWorkbook.Path & "\p102_triangles.txt" For Input As #1
  7.     a = Split(Input(LOF(1), #1), vbLf)  '提取全部字符串并按[回车换行]拆分为数组 Get all
  8.     Close #1
  9.    
  10.     m = UBound(a) - 1: n = 6
  11.     ReDim ar(m, n + 2)
  12.     For i = 0 To m
  13.         For j = 0 To n - 1
  14.             tr = Split(a(i), ",")
  15.             ar(i, j + 1) = Val(tr(j))
  16.         Next
  17.         ar(i, n + 1) = ar(i, 1): ar(i, n + 2) = ar(i, 2)
  18.     Next
  19.    
  20.     For i = 0 To m
  21.         r = "" '向量关系初始化
  22.         For j = 1 To 5 Step 2
  23.             t = PLineRel(ar(i, j), ar(i, j + 1), ar(i, j + 2), ar(i, j + 3), 0, 0)
  24.             If r = "" Then If t <> "=" Then r = t '记录非重叠的向量关系类型
  25.             If t <> "=" And t <> r Then Exit For '如有类型不同则不符合退出
  26.         Next
  27.         If j = 7 Then ar(i, 0) = 1: cnt = cnt + 1 '都是相同类型(含重叠)时即为被包含关系
  28.     Next
  29.     Debug.Print cnt
  30.     [a5].Resize(m + 1, n + 1) = ar
  31.     MsgBox cnt
  32. End Sub
复制代码
回复

使用道具 举报

 楼主| 发表于 2017-12-30 19:15 | 显示全部楼层
228,结果正确。
回复

使用道具 举报

 楼主| 发表于 2017-12-30 19:19 | 显示全部楼层
为什么代码又帖不了,又有关键词过不了关?

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

小黑屋|手机版|Archiver|Excel精英培训 ( 豫ICP备11015029号 )

GMT+8, 2024-4-16 12:19 , Processed in 0.277109 second(s), 5 queries , Gzip On, Yac On.

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表