欧拉计划 发表于 2016-8-17 18:10:16

题目102:文件中的三角形中有多少个内部包含原点?

Triangle containment

Three distinct points are plotted at random on a Cartesian plane, for which -1000 ≤ x, y ≤ 1000, such that a triangle is formed.

Consider the following two triangles:

A(-340,495), B(-153,-910), C(835,-947)

X(-175,41), Y(-421,-714), Z(574,-645)

It can be verified that triangle ABC contains the origin, whereas triangle XYZ does not.

Using triangles.txt (right click and 'Save Link/Target As...'), a 27K text file containing the co-ordinates of one thousand "random" triangles, find the number of triangles for which the interior contains the origin.

NOTE: The first two examples in the file represent the triangles in the example given above.

题目:

在笛卡尔平面上随机取三个不同的点,其中 -1000 ≤ x, y ≤ 1000,会形成一个三角形。

考虑如下两个三角形:

A(-340,495), B(-153,-910), C(835,-947)

X(-175,41), Y(-421,-714), Z(574,-645)

可以证明三角形 ABC 包含原点在其内部,而三角形 XYZ 则不包含。
包含一千个随机三角形,求其中有多少个三角形的内部包含原点。

注意:文件中的前两个三角形即为上述例子中的三角形。

jerryxjr1220 发表于 2017-1-7 10:52:59

这题的思路是利用同向法求点是否包含在三角形内部:

http://pic002.cnblogs.com/img/zdd/201008/2010080517445256.png
假设点P位于三角形内,会有这样一个规律,当我们沿着ABCA的方向在三条边上行走时,你会发现点P始终位于边AB,BC和CA的右侧。我们就利用这一点,但是如何判断一个点在线段的左侧还是右侧呢?我们可以从另一个角度来思考,当选定线段AB时,点C位于AB的右侧,同理选定BC时,点A位于BC的右侧,最后选定CA时,点B位于CA的右侧,所以当选择某一条边时,我们只需验证点P与该边所对的点在同一侧即可。问题又来了,如何判断两个点在某条线段的同一侧呢?

两点p1(x1,y1),p2(x2,y2),判断点p(x,y)在线的左边还是右边:

Tmp = (y1 – y2) * x + (x2 – x1) * y + x1 * y2 – x2 * y1
Tmp > 0 在左侧
Tmp = 0 在线上
Tmp < 0 在右侧

所以,有了方法写程序就很简单了:
# -*- coding: utf-8 -*-
"""
Created on Sat Jan7 09:41:55 2017

@author: Jerry Xu
"""

def tend(a,b,p):
    x1,y1 = a
    x2,y2 = b
    x, y= p
    return (y1-y2)*x + (x2-x1)*y + x1*y2 -x2*y1
   
def judge(a,b,c):
    d1 = tend(a,b,(0,0))
    d2 = tend(b,c,(0,0))
    d3 = tend(c,a,(0,0))
    if (d1>0 and d2>0 and d3>0) or (d1<0 and d2<0 and d3<0): #我们只需判断是否同向即可,都左或者都右都可以。
      return True
    else:
      return False

c = 0
with open('p102_triangles.txt') as f:
    lines = f.readlines()
for line in lines:
    line = line.strip('\n').split(',')
    A = (int(line),int(line))
    B = (int(line),int(line))
    C = (int(line),int(line))
    if judge(A,B,C):
      c += 1
print (c)
输出:
228

芒果加黄桃 发表于 2017-3-15 11:01:57

# encoding:utf-8
# 面积法
from time import time
from math import sqrt
P = (0, 0)
def calArea(A, B, C):
    a = sqrt((A - B) ** 2 + (A - B) ** 2)
    b = sqrt((A - C) ** 2 + (A - C) ** 2)
    c = sqrt((B - C) ** 2 + (B - C) ** 2)
    p = (a + b + c) / 2
    return sqrt(p * (p - a) * (p - b) * (p - c))
def isInTri(points):
    A, B, C = (points, points), (points, points), (points, points)
    area_ac = calArea(P, A, C)
    area_bc = calArea(P, B, C)
    area_ab = calArea(P, A, B)
    area_bac = calArea(A, B, C)
    if abs(area_ac + area_ab + area_bc - area_bac) < 0.00001:
      return True
def euler102():
    count = 0
    with open('p102_triangles.txt') as file:
      for line in file:
            points =
            if isInTri(points):
                print(points)
                count += 1
    print(count)
if __name__ == '__main__':
    start = time()
    euler102()
    print('cost %.6f sec' % (time() - start))

228
cost 0.058000 sec

芒果加黄桃 发表于 2017-3-15 11:06:39

# encoding:utf-8
# 重心法
from time import time
class Vector2:
    def __init__(self, t):
      self.x = t
      self.y = t
    def minus(self, t):
      return Vector2((self.x - t.x, self.y - t.y))   
    def dot(self, t):
      return self.x * t.x + self.y * t.y
P = Vector2((0, 0))
def isInTri(A, B, C):
    v0 = C.minus(A)
    v1 = B.minus(A)
    v2 = P.minus(A)
    dot00 = v0.dot(v0)
    dot01 = v0.dot(v1)
    dot02 = v0.dot(v2)
    dot11 = v1.dot(v1)
    dot12 = v1.dot(v2)
    div = 1 / (dot00 * dot11 - dot01 * dot01)
    u = (dot11 * dot02 - dot01 * dot12) * div
    if u <= 0 or u >= 1:
      return False
    v = (dot00 * dot12 - dot01 * dot02) * div
    if v <= 0 or v >= 1:
      return False
    return u + v < 1
def euler102():
    count = 0
    with open('p102_triangles.txt') as file:
      for line in file:
            tmp = line.replace('\n', '').split(',')
            A = Vector2((int(tmp), int(tmp)))
            B = Vector2((int(tmp), int(tmp)))
            C = Vector2((int(tmp), int(tmp)))
            if isInTri(A, B, C):
                print(tmp)
                count += 1
    print(count)
if __name__ == '__main__':
    start = time()
    euler102()
    print('cost %.6f sec' % (time() - start))

debuggerzh 发表于 2021-7-18 08:37:03

异端方法
https://i.loli.net/2021/07/18/3RitJX2wer16x5T.png

guosl 发表于 2022-1-29 10:26:43

利用内积的性质。
/*
答案:228
*/
#include <cstdio>

int main(void)
{
errno_t err;
FILE *fp = NULL;
err = fopen_s(&fp, "p102_triangles.txt", "r");//打开文件
if (err != 0)
{
    printf_s("数据文件未打开\n");
    return 0;
}
int x, y;
int nCount = 0;
while (fscanf_s(fp, "%d,%d,%d,%d,%d,%d", &x, &y, &x, &y, &x, &y) != EOF)
{
    int d1 = x * y - x * y;
    int d2 = x * y - x * y;
    int d3= x * y - x * y;
    if (d1 > 0 && d2 > 0 && d3 > 0 || d1 < 0 && d2 < 0 && d3 < 0)
      ++nCount;
}
fclose(fp);
printf_s("%d\n", nCount);
return 0;
}
页: [1]
查看完整版本: 题目102:文件中的三角形中有多少个内部包含原点?