几何算法:Morley's Theorem

我记得刚读高中时,当时应该还在军训,没有正式上课。晚自习的时候,数学老师出了几道难度颇大的平面几何题,其中一题是证明Morley's Theorem:做三角形ABC每个内角的三等分线,相交成三角形DEF,则DEF是等边三角形。如图:


几何算法:Morley's Theorem_第1张图片

几何算法:Morley's Theorem_第2张图片

UVa利用这个定理出了这样一道题:根据ABC的顶点坐标来计算DEF的顶点坐标(需要逆时针输入顶点坐标)。

这道题目没有用到什么算法,只需要根据题意计算。根据向量的基本计算,可以求出ABC的边的向量以及内角,然后旋转1/3的内角就可以得到三等分线的向量,再去计算直线的交点。

关于基础计算的代码,在上篇文章中都已给出,这里直接切入问题内核。
···
class Morley {

static Point getPoint(Point a, Point b, Point c) {
    Vector v1 = c.substract(b);
    double rad1 = Vector.angle(a.substract(b), v1);
    v1 = Vector.rotate(v1, rad1 / 3);

    Vector v2 = b.substract(c);
    double rad2 = Vector.angle(a.substract(c), v2);
    v2 = Vector.rotate(v2, -rad2 / 3); // 负数表示顺时针旋转
    return Vector.getLineIntersection(b, v1, c, v2);
}

public static void main(String[] args) {
    Scanner in = new Scanner(System.in);
    int n = in.nextInt();
    in.nextLine(); // 过滤掉\n

    while (n-- > 0) {
        String str = in.nextLine();
        List list = Stream.of(str.split("\\s+")).map(Double::parseDouble).collect(Collectors.toList());
        System.out.println(list);
        Point a = create(list.get(0), list.get(1));
        Point b = create(list.get(2), list.get(3));
        Point c = create(list.get(4), list.get(5));
        Point d = getPoint(a, b, c);
        Point e = getPoint(b, c, a);
        Point f = getPoint(c, a, b);
        System.out.printf("%f %f %f %f %f %f\n", d.x, d.y, e.x, e.y, f.x, f.y);
    }
}

}
···
算法充分利用了定理的对称性,既可以减少思考,又可以复用代码。

测试数据(亲测无误):

Sample Input
2
1 1 2 2 1 2
0 0 100 0 50 50
Sample Output
1.316987 1.816987 1.183013 1.683013 1.366025 1.633975
56.698730 25.000000 43.301270 25.000000 50.000000 13.397460

还是回到十几年前的那个晚上,我无法证明这道难题,但是却觉得数学非常神奇。随后我就忘了这道题。等我上了大学,在图书馆中才无意间看到了这道题目的证明,也想起了当年的那位老师。

参考:《算法竞赛入门经典训练指南》

你可能感兴趣的:(几何算法:Morley's Theorem)