피타고라스 삼각형 쌓기


23

배경

피타고라스 삼각형은 각 변의 길이가 정수인 오른쪽 삼각형입니다 (즉, 변의 길이는 피타고라스의 삼중 항을 이룹니다 ).

피타고라스 삼각형

이 삼각형의 변을 사용하여 다음과 같이 두 가지 비 합치 피타고라스 삼각형을 추가 할 수 있습니다.

트라이앵글 스택 1

두 개의 삼각형이 겹치지 않고 연결면의 길이가 동일한 한이 패턴을 계속 사용할 수 있습니다.

여기에 이미지 설명을 입력하십시오

문제는 주어진 공간에 맞지 않는 피타고라스 삼각형을 몇 개나 넣을 수 있습니까?

입력

당신은 입력으로 두 개의 정수를받을 것 WH, 함수 인수, STDIN, 문자열을 통해, 또는 같은 당신이 무엇을. 정수는 10 진수, 16 진수, 2 진수, 단항 (행운, 망막 ) 또는 기타 정수 기준 으로 수신 될 수 있습니다 . 당신은 그것을 가정 할 수 있습니다 max(W, H) <= 2^15 - 1.

출력

프로그램 또는 함수는 겹치지 않는 연결된 비 동일 피타고라스 삼각형의 목록을 계산하고 각각 세 좌표 세트의 목록을 출력해야합니다. 여기서 세트의 좌표는 선으로 연결될 때 피타고라스 삼각형 중 하나를 형성합니다. 우리의 공간 (좌표는 실수해야 x간격에 있어야 [0, W]y간격에 있어야합니다 [0, H]), 거리 기계 정밀도에 정확해야한다. 삼각형의 순서와 각 좌표의 정확한 형식은 중요하지 않습니다.

연결된 경계를 넘어서서 만 하나의 삼각형에서 다른 삼각형으로 "걸을"수 있어야합니다.

예를 들어, 상기 도면을 사용하여, 우리의 입력이 될 수 있도록 W = 60, H = 60.

출력은 다음과 같은 좌표 목록이 될 수 있습니다.

(0, 15), (0, 21), (8, 15)
(0, 21), (14.4, 40.2), (8, 15)
(0, 15), (8, 0), (8, 15)
(8, 0), (8, 15), (28, 15)
(8, 15), (28, 15), (28, 36)
(28, 15), (28, 36), (56, 36)

이제 6 개의 삼각형은 공간을 확보 할 수있는 최선의 방법이 아닙니다. 더 잘할 수 있습니까?

규칙과 채점

  • 이 챌린지에 대한 점수는 프로그램이 입력 한 삼각형 수입니다 W = 1000, H = 1000. 누군가이 사례를 하드 코딩하는 것으로 의심되면이 입력을 변경할 권리가 있습니다.

  • 피타고라스 트리플을 계산하는 내장을 사용할 수 없으며, 피타고라스 트리플을 2 개 이상의 목록으로 하드 코딩 할 수 없습니다. 괜찮다).

  • 어떤 언어로든 제출물을 작성할 수 있습니다. 가독성과 의견 수렴이 권장됩니다.

  • 피타고라스 트리플의 목록은 여기에서 찾을 수 있습니다 .

  • 표준 허점 은 허용되지 않습니다.


공간 내에서 같은 삼각형의 인스턴스를 두 개 이상 사용할 수 있습니까?
DavidC

1
@DavidCarraher 프로그램에서 생성 된 두 개의 삼각형이 서로 일치하지 않을 수 있습니다.
BrainSteel

3
이것은 관심이있을 수 있습니다 : en.wikipedia.org/wiki/Tree_of_primitive_Pythagorean_triples
Level River St

이 문제에는 많은 계산이 필요합니까? 특히 이것은 포장 문제
Renae Lider

1
@KeithRandall 그들은 비슷하지만 합동이 아닙니다.
Geobits

답변:


16

파이썬 3, 109

이것은 확실히 어려운 도전이었습니다. 기본 지오메트리 능력에 의문을 품은 코드를 여러 번 작성했습니다. 즉, 결과에 매우 만족합니다. 삼각형을 배치하기위한 복잡한 알고리즘을 만들려고 노력하지 않았으며 대신 내 코드는 항상 가장 작은 것을 배치하여 실수합니다. 나중에 이것을 개선 할 수 있기를 바랍니다. 그렇지 않으면 더 나은 알고리즘을 찾기 위해 다른 사람들을 자극 할 것입니다! 대체로 매우 재미있는 문제이며 재미있는 사진을 만듭니다.

코드는 다음과 같습니다.

import time
import math

W = int(input("Enter W: "))
H = int(input("Enter H: "))

middle_x = math.floor(W/2)
middle_y = math.floor(H/2)

sides = [ # each side is in the format [length, [x0, y0], [x1, y1]]
    [3,[middle_x,middle_y],[middle_x+3,middle_y]],
    [4,[middle_x,middle_y],[middle_x,middle_y+4]],
    [5,[middle_x+3,middle_y],[middle_x,middle_y+4]]
    ]

triangles = [[0,1,2]] # each triangle is in the format [a, b, c] where a, b and c are the indexes of sides

used_triangles = [[3,4,5]] # a list of used Pythagorean triples, where lengths are ordered (a < b < c)

max_bounds_length = math.sqrt(W**2 + H**2)

def check_if_pyth_triple(a,b): # accepts two lists of the form [l, [x0,y0], [x1,y1]] defining two line segments
    # returns 0 if there are no triples, 1 if there is a triple with a right angle on a,
    # and 2 if there is a triple with the right angle opposite a
    c = math.sqrt(a[0]**2 + b[0]**2)
    if c.is_integer():
        if not sorted([a[0], b[0], c]) in used_triangles:
            return 1
        return 0
    else:
        if a[0] > b[0]:
            c = math.sqrt(a[0]**2 - b[0]**2)
            if c.is_integer() and not sorted([a[0], b[0], c]) in used_triangles:
                return 2
        return 0

def check_if_out_of_bounds(p):
    out = False
    if p[0] < 0 or p[0] > W:
        out = True
    if p[1] < 0 or p[1] > H:
        out = True
    return out

def in_between(a,b,c):
    maxi = max(a,c)
    mini = min(a,c)
    return mini < b < maxi

def sides_intersect(AB,CD): # accepts two lists of the form [l, [x0,y0], [x1,y1]] defining two line segments
    # doesn't count overlapping lines
    A = AB[1]
    B = AB[2]
    C = CD[1]
    D = CD[2]

    if A[0] == B[0]: # AB is vertical
        if C[0] == D[0]: # CD is vertical
            return False
        else:
            m1 = (C[1] - D[1])/(C[0] - D[0]) # slope of CD
            y = m1*(A[0] - C[0]) + C[1] # the y value of CD at AB's x value
            return in_between(A[1], y, B[1]) and in_between(C[0], A[0], D[0])
    else:
        m0 = (A[1] - B[1])/(A[0] - B[0]) # slope of AB
        if C[0] == D[0]: # CD is vertical
            y = m0*(C[0] - A[0]) + A[1] # the y value of CD at AB's x value
            return in_between(C[1], y, D[1]) and in_between(A[0],C[0],B[0])
        else:
            m1 = (C[1] - D[1])/(C[0] - D[0]) # slope of CD
            if m0 == m1:
                return False
            else:
                x = (m0*A[0] - m1*C[0] - A[1] + C[1])/(m0 - m1)
                return in_between(A[0], x, B[0]) and in_between(C[0], x, D[0])

def check_all_sides(b,triangle):
    no_intersections = True
    for side in sides:
        if sides_intersect(side, b):
            no_intersections = False
            break

    return no_intersections

def check_point_still_has_room(A): # This function is needed for the weird case when all 2pi degrees
    # around a point are filled by triangles, but you could fit in a small triangle into another one
    # already built around the point. Doing this won't cause sides_intersect() to detect it because
    # the sides will all be parallel. Crazy stuff.
    connecting_sides = []
    for side in sides:
        if A in side:
            connecting_sides.append(side)

    match_count = 0
    slopes = []
    for side in connecting_sides:
        B = side[1]
        if A == B:
            B = side[2]
        if not A[0] == B[0]:
            slope = round((A[1]-B[1])/(A[0]-B[0]),4)
        else:
            if A[1] < B[1]:
                slope = "infinity"
            else:
                slope = "neg_infinity"
        if slope in slopes:
            match_count -= 1
        else:
            slopes.append(slope)
            match_count += 1

    return match_count != 0

def construct_b(a,b,pyth_triple_info,straight_b_direction,bent_b_direction):
    # this function finds the correct third point of the triangle given a and the length of b
    # pyth_triple_info determines if a is a leg or the hypotenuse
    # the b_directions determine on which side of a the triangle should be formed
    a_p = 2 # this is the index of the point in a that is not the shared point with b
    if a[1] != b[1]:
        a_p = 1

    vx = a[a_p][0] - b[1][0] # v is our vector, and these are the coordinates, adjusted so that
    vy = a[a_p][1] - b[1][1] # the shared point is the origin

    if pyth_triple_info == 1:
        # because the dot product of orthogonal vectors is zero, we can use that and the Pythagorean formula
        # to get this simple formula for generating the coordinates of b's second point
        if vy == 0:
            x = 0
            y = b[0]
        else:
            x = b[0]/math.sqrt(1+((-vx/vy)**2)) # b[0] is the desired length
            y = -vx*x/vy

        x = x*straight_b_direction # since the vector is orthagonal, if we want to reverse the direction,
        y = y*straight_b_direction # it just means finding the mirror point

    elif pyth_triple_info == 2: # this finds the intersection of the two circles of radii b[0] and c 
        # around a's endpoints, which is the third point of the triangle if a is the hypotenuse
        c = math.sqrt(a[0]**2 - b[0]**2)
        D = a[0]
        A = (b[0]**2 - c**2 + D**2 ) / (2*D)
        h = math.sqrt(b[0]**2 - A**2)
        x2 = vx*(A/D)
        y2 = vy*(A/D)        
        x = x2 + h*vy/D
        y = y2 - h*vx/D

        if bent_b_direction == -1: # this constitutes reflection of the vector (-x,-y) around the normal vector n,
            # which accounts for finding the triangle on the opposite side of a
            dx = -x
            dy = -y
            v_length = math.sqrt(vx**2 + vy**2)
            nx = vx/v_length
            ny = vy/v_length

            d_dot_n = dx*nx + dy*ny

            x = dx - 2*d_dot_n*nx
            y = dy - 2*d_dot_n*ny

    x = x + b[1][0] # adjust back to the original frame
    y = y + b[1][1]

    return [x,y]

def construct_triangle(side_index):
    a = sides[side_index] # a is the base of the triangle
    a_p = 1
    b = [1, a[a_p], []] # side b, c is hypotenuse

    for index, triangle in enumerate(triangles):
        if side_index in triangle:
            triangle_index = index
            break

    triangle = list(triangles[triangle_index])
    triangle.remove(side_index)

    add_tri = False

    straight_b = construct_b(a,b,1,1,1)

    bent_b = construct_b(a,b,2,1,1)

    A = sides[triangle[0]][1]
    if A in a:
        A = sides[triangle[0]][2]

    Ax = A[0] - b[1][0] # adjusting A so that it's a vector
    Ay = A[1] - b[1][1]

    # these are for determining if construct_b() is going to the correct side
    triangle_on_side = (a[2][0]-a[1][0])*(A[1]-a[1][1]) - (a[2][1]-a[1][1])*(A[0]-a[1][0])
    straight_b_on_side = (a[2][0]-a[1][0])*(straight_b[1]-a[1][1]) - (a[2][1]-a[1][1])*(straight_b[0]-a[1][0])
    bent_b_on_side = (a[2][0]-a[1][0])*(bent_b[1]-a[1][1]) - (a[2][1]-a[1][1])*(bent_b[0]-a[1][0])

    straight_b_direction = 1
    if (triangle_on_side > 0 and straight_b_on_side > 0) or (triangle_on_side < 0 and straight_b_on_side < 0):
        straight_b_direction = -1

    bent_b_direction = 1
    if (triangle_on_side > 0 and bent_b_on_side > 0) or (triangle_on_side < 0 and bent_b_on_side < 0):
        bent_b_direction = -1


    a_ps = []
    for x in [1,2]:
        if check_point_still_has_room(a[x]): # here we check for that weird exception
            a_ps.append(x)

    while True:
        out_of_bounds = False
        if b[0] > max_bounds_length:
            break

        pyth_triple_info = check_if_pyth_triple(a,b)

        for a_p in a_ps:
            if a_p == 1: # this accounts for the change in direction when switching a's points
                new_bent_b_direction = bent_b_direction
            else:
                new_bent_b_direction = -bent_b_direction

            b[1] = a[a_p]
            if pyth_triple_info > 0:
                b[2] = construct_b(a,b,pyth_triple_info,straight_b_direction,new_bent_b_direction)

                if check_if_out_of_bounds(b[2]): # here is the check to make sure we don't go out of bounds
                    out_of_bounds = True
                    break

                if check_all_sides(b,triangle):
                    if pyth_triple_info == 1:
                        c = [math.sqrt(a[0]**2 + b[0]**2), a[3-a_p], b[2]]
                    else:
                        c = [math.sqrt(a[0]**2 - b[0]**2), a[3-a_p], b[2]]

                    if check_all_sides(c,triangle):
                        add_tri = True
                        break

        if out_of_bounds or add_tri:
            break

        b[0] += 1 # increment the length of b every time the loop goes through

    if add_tri: # this adds a new triangle
        sides.append(b)
        sides.append(c)
        sides_len = len(sides)
        triangles.append([side_index, sides_len - 2, sides_len - 1])
        used_triangles.append(sorted([a[0], b[0], c[0]])) # so we don't use the same triangle again

def build_all_triangles(): # this iterates through every side to see if a new triangle can be constructed
    # this is probably where real optimization would take place so more optimal triangles are placed first
    t0 = time.clock()

    index = 0
    while index < len(sides):
        construct_triangle(index)
        index += 1

    t1 = time.clock()

    triangles_points = [] # this is all for printing points
    for triangle in triangles:
        point_list = []
        for x in [1,2]:
            for side_index in triangle:
                point = sides[side_index][x]
                if not point in point_list:
                    point_list.append(point)
        triangles_points.append(point_list)

    for triangle in triangles_points:
        print(triangle)

    print(len(triangles), "triangles placed in", round(t1-t0,3), "seconds.")

def matplotlib_graph(): # this displays the triangles with matplotlib
    import pylab as pl
    import matplotlib.pyplot as plt
    from matplotlib import collections as mc

    lines = []
    for side in sides:
        lines.append([side[1],side[2]])

    lc = mc.LineCollection(lines)
    fig, ax = pl.subplots()
    ax.add_collection(lc)
    ax.autoscale()
    ax.margins(0.1)
    plt.show()

build_all_triangles()

여기에서의 출력의 그래프이다 W = 1000H = 1000109 개 삼각형은 : matplotlib로 플로팅 된 삼각형의 그래프

여기 W = 10000H = 10000724 개 삼각형 : matplotlib로 플로팅 된 삼각형의 그래프

삼각형을 그래프로 그린 matplotlib_graph()후 함수를 호출하십시오 build_all_triangles().

에 : 나는 합리적으로 빠른 코드 실행 생각 W = 1000H = 1000는 0.66 초 정도 걸립니다, 그리고에서 W = 10000H = 10000내 엉터리 노트북을 사용 45초 걸립니다.


솔루션을 완성해야합니다. 나는 몇 주 전에 꽤 멀리 있었지만 결코 완성을 얻지 못했습니다. 정말 많은 작업입니다! 특히 교차점 테스트를 통해 퇴화 사례에 대해 올바르게 작동하도록합니다. 나는 그것을 위해 어떤 접근법을 사용하고 싶은지 알고 있지만 아직 끝나지 않은 부분입니다.
Reto Koradi

1
와우, 이것은 훌륭한 첫 번째 해결책입니다! 나는 특히 그래프를 좋아한다. 이 도전을 즐겼다 니 다행이며 PPCG를 고수하기를 바랍니다.
BrainSteel

아마 내가 본 것 중에 가장 혼란스러운 이미지 일 것입니다
Beta Decay

16

C ++, 146 삼각형 (1/2)

이미지 결과

결과

알고리즘 설명

솔루션 공간에 대한 폭 넓은 우선 검색을 사용합니다. 각 단계에서는 k상자에 맞는 삼각형의 모든 고유 한 구성으로 시작 k + 1하고 사용되지 않은 삼각형을 구성에 추가하는 모든 옵션을 열거 하여 삼각형의 모든 고유 한 구성을 만듭니다 .

알고리즘은 기본적으로 철저한 BFS로 절대 최대 값을 찾도록 설정됩니다. 더 작은 크기에서도 성공적으로 수행됩니다. 예를 들어, 50x50 상자의 경우 약 1 분 안에 최대 값을 찾습니다. 그러나 1000x1000의 경우 솔루션 공간이 너무 큽니다. 종료하기 위해 각 단계 후에 솔루션 목록을 정리합니다. 유지되는 솔루션 수는 명령 행 인수로 제공됩니다. 위의 솔루션에 대해 값 50이 사용되었습니다. 결과적으로 약 10 분의 런타임이 발생했습니다.

주요 단계의 개요는 다음과 같습니다.

  1. 상자 안에 들어갈 수있는 피타고라스 삼각형을 모두 생성하십시오.
  2. 각각 1 개의 삼각형이있는 솔루션으로 구성된 초기 솔루션 세트를 생성하십시오.
  3. 루프 오버 세대 (삼각수).
    1. 솔루션 세트에서 유효하지 않은 솔루션을 제거하십시오. 이들은 상자 안에 들어 가지 않거나 겹치는 솔루션입니다.
    2. 솔루션 세트가 비어 있으면 완료됩니다. 이전 세대의 솔루션 세트에는 최대 값이 포함되어 있습니다.
    3. 트림 옵션이 활성화 된 경우 트림 솔루션이 지정된 크기로 설정되었습니다.
    4. 현재 세대의 모든 솔루션을 반복합니다.
      1. 솔루션 주변의 모든면을 반복합니다.
        1. 둘레와 변의 길이가 같고 아직 해에없는 삼각형을 모두 찾으십시오.
        2. 삼각형을 추가하여 새로운 솔루션을 생성하고 새로운 세대의 솔루션 세트에 솔루션을 추가하십시오.
  4. 인쇄 솔루션.

전체 체계의 중요한 측면 중 하나는 구성이 일반적으로 여러 번 생성되며 고유 한 구성에만 관심이 있다는 것입니다. 따라서 솔루션을 정의하는 고유 키가 필요합니다. 솔루션을 생성하는 동안 사용 된 삼각형의 순서와 무관해야합니다. 예를 들어, 키에 좌표를 사용하면 전혀 작동하지 않습니다. 여러 솔루션으로 동일한 솔루션에 도달하면 완전히 다를 수 있기 때문입니다. 내가 사용한 것은 전체 목록의 삼각형 인덱스와 삼각형 연결 방법을 정의하는 "커넥터"개체 세트입니다. 따라서이 키는 2D 공간에서의 구성 순서 및 위치와 상관없이 토폴로지 만 인코딩합니다.

더 많은 구현 측면이 있지만, 사소한 것이 아닌 다른 부분은 전체가 주어진 상자에 맞는지 여부와 방법을 결정하는 것입니다. 실제로 경계를 밀고 싶다면 상자 안에 회전을 넣을 수 있어야합니다.

누군가 가이 모든 작동 방식에 대한 세부 사항을 자세히 알고 싶을 경우 나중에 2 부의 코드에 주석을 추가하려고합니다.

공식 텍스트 형식의 결과

(322.085, 641.587) (318.105, 641.979) (321.791, 638.602)
(318.105, 641.979) (309.998, 633.131) (321.791, 638.602)
(318.105, 641.979) (303.362, 639.211) (309.998, 633.131)
(318.105, 641.979) (301.886, 647.073) (303.362, 639.211)
(301.886, 647.073) (297.465, 638.103) (303.362, 639.211)
(301.886, 647.073) (280.358, 657.682) (297.465, 638.103)
(301.886, 647.073) (283.452, 663.961) (280.358, 657.682)
(301.886, 647.073) (298.195, 666.730) (283.452, 663.961)
(301.886, 647.073) (308.959, 661.425) (298.195, 666.730)
(301.886, 647.073) (335.868, 648.164) (308.959, 661.425)
(335.868, 648.164) (325.012, 669.568) (308.959, 661.425)
(308.959, 661.425) (313.666, 698.124) (298.195, 666.730)
(313.666, 698.124) (293.027, 694.249) (298.195, 666.730)
(313.666, 698.124) (289.336, 713.905) (293.027, 694.249)
(298.195, 666.730) (276.808, 699.343) (283.452, 663.961)
(335.868, 648.164) (353.550, 684.043) (325.012, 669.568)
(303.362, 639.211) (276.341, 609.717) (309.998, 633.131)
(276.808, 699.343) (250.272, 694.360) (283.452, 663.961)
(335.868, 648.164) (362.778, 634.902) (353.550, 684.043)
(362.778, 634.902) (367.483, 682.671) (353.550, 684.043)
(250.272, 694.360) (234.060, 676.664) (283.452, 663.961)
(362.778, 634.902) (382.682, 632.942) (367.483, 682.671)
(382.682, 632.942) (419.979, 644.341) (367.483, 682.671)
(419.979, 644.341) (379.809, 692.873) (367.483, 682.671)
(353.550, 684.043) (326.409, 737.553) (325.012, 669.568)
(353.550, 684.043) (361.864, 731.318) (326.409, 737.553)
(353.550, 684.043) (416.033, 721.791) (361.864, 731.318)
(416.033, 721.791) (385.938, 753.889) (361.864, 731.318)
(385.938, 753.889) (323.561, 772.170) (361.864, 731.318)
(385.938, 753.889) (383.201, 778.739) (323.561, 772.170)
(383.201, 778.739) (381.996, 789.673) (323.561, 772.170)
(323.561, 772.170) (292.922, 743.443) (361.864, 731.318)
(323.561, 772.170) (296.202, 801.350) (292.922, 743.443)
(250.272, 694.360) (182.446, 723.951) (234.060, 676.664)
(335.868, 648.164) (330.951, 570.319) (362.778, 634.902)
(330.951, 570.319) (381.615, 625.619) (362.778, 634.902)
(330.951, 570.319) (375.734, 565.908) (381.615, 625.619)
(330.951, 570.319) (372.989, 538.043) (375.734, 565.908)
(323.561, 772.170) (350.914, 852.648) (296.202, 801.350)
(323.561, 772.170) (362.438, 846.632) (350.914, 852.648)
(234.060, 676.664) (217.123, 610.807) (283.452, 663.961)
(217.123, 610.807) (249.415, 594.893) (283.452, 663.961)
(375.734, 565.908) (438.431, 559.733) (381.615, 625.619)
(382.682, 632.942) (443.362, 567.835) (419.979, 644.341)
(443.362, 567.835) (471.667, 606.601) (419.979, 644.341)
(323.561, 772.170) (393.464, 830.433) (362.438, 846.632)
(372.989, 538.043) (471.272, 556.499) (375.734, 565.908)
(372.989, 538.043) (444.749, 502.679) (471.272, 556.499)
(372.989, 538.043) (365.033, 521.897) (444.749, 502.679)
(443.362, 567.835) (544.353, 553.528) (471.667, 606.601)
(544.353, 553.528) (523.309, 622.384) (471.667, 606.601)
(544.353, 553.528) (606.515, 572.527) (523.309, 622.384)
(419.979, 644.341) (484.688, 697.901) (379.809, 692.873)
(444.749, 502.679) (552.898, 516.272) (471.272, 556.499)
(217.123, 610.807) (170.708, 516.623) (249.415, 594.893)
(484.688, 697.901) (482.006, 753.837) (379.809, 692.873)
(484.688, 697.901) (571.903, 758.147) (482.006, 753.837)
(419.979, 644.341) (535.698, 636.273) (484.688, 697.901)
(276.808, 699.343) (228.126, 812.299) (250.272, 694.360)
(228.126, 812.299) (185.689, 726.188) (250.272, 694.360)
(228.126, 812.299) (192.246, 829.981) (185.689, 726.188)
(393.464, 830.433) (449.003, 936.807) (362.438, 846.632)
(393.464, 830.433) (468.505, 926.625) (449.003, 936.807)
(416.033, 721.791) (471.289, 833.915) (385.938, 753.889)
(471.289, 833.915) (430.252, 852.379) (385.938, 753.889)
(350.914, 852.648) (227.804, 874.300) (296.202, 801.350)
(192.246, 829.981) (114.401, 834.898) (185.689, 726.188)
(114.401, 834.898) (155.433, 715.767) (185.689, 726.188)
(217.123, 610.807) (91.773, 555.523) (170.708, 516.623)
(91.773, 555.523) (141.533, 457.421) (170.708, 516.623)
(141.533, 457.421) (241.996, 407.912) (170.708, 516.623)
(141.533, 457.421) (235.365, 394.457) (241.996, 407.912)
(241.996, 407.912) (219.849, 525.851) (170.708, 516.623)
(241.996, 407.912) (304.896, 419.724) (219.849, 525.851)
(91.773, 555.523) (55.917, 413.995) (141.533, 457.421)
(571.903, 758.147) (476.260, 873.699) (482.006, 753.837)
(571.903, 758.147) (514.819, 890.349) (476.260, 873.699)
(571.903, 758.147) (587.510, 764.886) (514.819, 890.349)
(587.510, 764.886) (537.290, 898.778) (514.819, 890.349)
(587.510, 764.886) (592.254, 896.801) (537.290, 898.778)
(587.510, 764.886) (672.455, 761.831) (592.254, 896.801)
(55.917, 413.995) (113.819, 299.840) (141.533, 457.421)
(113.819, 299.840) (149.275, 293.604) (141.533, 457.421)
(544.353, 553.528) (652.112, 423.339) (606.515, 572.527)
(652.112, 423.339) (698.333, 461.597) (606.515, 572.527)
(535.698, 636.273) (651.250, 731.917) (484.688, 697.901)
(651.250, 731.917) (642.213, 756.296) (484.688, 697.901)
(304.896, 419.724) (299.444, 589.636) (219.849, 525.851)
(304.896, 419.724) (369.108, 452.294) (299.444, 589.636)
(304.896, 419.724) (365.965, 299.326) (369.108, 452.294)
(304.896, 419.724) (269.090, 347.067) (365.965, 299.326)
(114.401, 834.898) (0.942, 795.820) (155.433, 715.767)
(114.401, 834.898) (75.649, 947.412) (0.942, 795.820)
(192.246, 829.981) (124.489, 994.580) (114.401, 834.898)
(269.090, 347.067) (205.435, 217.901) (365.965, 299.326)
(205.435, 217.901) (214.030, 200.956) (365.965, 299.326)
(182.446, 723.951) (68.958, 600.078) (234.060, 676.664)
(182.446, 723.951) (32.828, 633.179) (68.958, 600.078)
(652.112, 423.339) (763.695, 288.528) (698.333, 461.597)
(763.695, 288.528) (808.220, 324.117) (698.333, 461.597)
(763.695, 288.528) (811.147, 229.162) (808.220, 324.117)
(652.112, 423.339) (627.572, 321.247) (763.695, 288.528)
(627.572, 321.247) (660.872, 244.129) (763.695, 288.528)
(652.112, 423.339) (530.342, 344.618) (627.572, 321.247)
(652.112, 423.339) (570.488, 453.449) (530.342, 344.618)
(627.572, 321.247) (503.633, 267.730) (660.872, 244.129)
(365.965, 299.326) (473.086, 450.157) (369.108, 452.294)
(365.965, 299.326) (506.922, 344.440) (473.086, 450.157)
(365.965, 299.326) (394.633, 260.827) (506.922, 344.440)
(394.633, 260.827) (537.381, 303.535) (506.922, 344.440)
(811.147, 229.162) (979.067, 234.338) (808.220, 324.117)
(698.333, 461.597) (706.660, 655.418) (606.515, 572.527)
(811.147, 229.162) (982.117, 135.385) (979.067, 234.338)
(982.117, 135.385) (999.058, 234.954) (979.067, 234.338)
(365.965, 299.326) (214.375, 186.448) (394.633, 260.827)
(811.147, 229.162) (803.145, 154.590) (982.117, 135.385)
(803.145, 154.590) (978.596, 102.573) (982.117, 135.385)
(214.375, 186.448) (314.969, 126.701) (394.633, 260.827)
(314.969, 126.701) (508.984, 192.909) (394.633, 260.827)
(314.969, 126.701) (338.497, 88.341) (508.984, 192.909)
(338.497, 88.341) (523.725, 138.884) (508.984, 192.909)
(338.497, 88.341) (359.556, 11.163) (523.725, 138.884)
(808.220, 324.117) (801.442, 544.012) (698.333, 461.597)
(801.442, 544.012) (739.631, 621.345) (698.333, 461.597)
(660.872, 244.129) (732.227, 78.877) (763.695, 288.528)
(660.872, 244.129) (644.092, 40.821) (732.227, 78.877)
(808.220, 324.117) (822.432, 544.659) (801.442, 544.012)
(660.872, 244.129) (559.380, 47.812) (644.092, 40.821)
(660.872, 244.129) (556.880, 242.796) (559.380, 47.812)
(556.880, 242.796) (528.882, 242.437) (559.380, 47.812)
(808.220, 324.117) (924.831, 449.189) (822.432, 544.659)
(924.831, 449.189) (922.677, 652.177) (822.432, 544.659)
(922.677, 652.177) (779.319, 785.836) (822.432, 544.659)
(779.319, 785.836) (696.630, 771.054) (822.432, 544.659)
(779.319, 785.836) (746.412, 969.918) (696.630, 771.054)
(779.319, 785.836) (848.467, 840.265) (746.412, 969.918)
(848.467, 840.265) (889.327, 872.428) (746.412, 969.918)
(746.412, 969.918) (619.097, 866.541) (696.630, 771.054)
(779.319, 785.836) (993.200, 656.395) (848.467, 840.265)
(993.200, 656.395) (935.157, 864.450) (848.467, 840.265)
(993.200, 656.395) (995.840, 881.379) (935.157, 864.450)
(338.497, 88.341) (34.607, 5.420) (359.556, 11.163)
(338.497, 88.341) (189.294, 204.357) (34.607, 5.420)
(189.294, 204.357) (158.507, 228.296) (34.607, 5.420)
(158.507, 228.296) (38.525, 230.386) (34.607, 5.420)
(158.507, 228.296) (41.694, 412.358) (38.525, 230.386)

암호

코드는 2 부를 참조하십시오. 이것은 포스트 크기 제한을 해결하기 위해 두 부분으로 나뉩니다.

이 코드는 PasteBin 에서도 사용할 수 있습니다 .


8

C ++, 146 개의 삼각형 (2/2 부)

부분 1부터 계속되었습니다. 이것은 포스트 크기 제한을 해결하기 위해 두 부분으로 나뉩니다.

암호

추가 할 설명입니다.

#include <cmath>
#include <vector>
#include <set>
#include <map>
#include <sstream>
#include <iostream>

class Vec2 {
public:
    Vec2()
      : m_x(0.0f), m_y(0.0f) {
    }

    Vec2(float x, float y)
      : m_x(x), m_y(y) {
    }

    float x() const {
        return m_x;
    }

    float y() const {
        return m_y;
    }

    void normalize() {
        float s = 1.0f / sqrt(m_x * m_x + m_y * m_y);
        m_x *= s;
        m_y *= s;
    }

    Vec2 operator+(const Vec2& rhs) const {
        return Vec2(m_x + rhs.m_x, m_y + rhs.m_y);
    }

    Vec2 operator-(const Vec2& rhs) const {
        return Vec2(m_x - rhs.m_x, m_y - rhs.m_y);
    }

    Vec2 operator*(float s) const {
        return Vec2(m_x * s, m_y * s);
    }

private:
    float m_x, m_y;
};

static float cross(const Vec2& v1, const Vec2& v2) {
    return v1.x() * v2.y() - v1.y() * v2.x();
}

class Triangle {
public:
    Triangle()
      : m_sideLenA(0), m_sideLenB(0), m_sideLenC(0) {
    }

    Triangle(int sideLenA, int sideLenB, int sideLenC)
      : m_sideLenA(sideLenA),
        m_sideLenB(sideLenB),
        m_sideLenC(sideLenC) {
    }

    int getSideLenA() const {
        return m_sideLenA;
    }

    int getSideLenB() const {
        return m_sideLenB;
    }

    int getSideLenC() const {
        return m_sideLenC;
    }

private:
    int m_sideLenA, m_sideLenB, m_sideLenC;
};

class Connector {
public:
    Connector(int sideLen, int triIdx1, int triIdx2, bool flipped);

    bool operator<(const Connector& rhs) const;

    void print() const {
        std::cout << m_sideLen << "/" << m_triIdx1 << "/"
                  << m_triIdx2 << "/" << m_flipped << " ";
    }

private:
    int m_sideLen;
    int m_triIdx1, m_triIdx2;
    bool m_flipped;
};

typedef std::vector<Triangle> TriangleVec;
typedef std::multimap<int, int> SideMap;

typedef std::set<int> TriangleSet;
typedef std::set<Connector> ConnectorSet;

class SolutionKey {
public:
    SolutionKey() {
    }

    void init(int triIdx);
    void add(int triIdx, const Connector& conn);

    bool containsTriangle(int triIdx) const;
    int minTriangle() const;

    bool operator<(const SolutionKey& rhs) const;

    void print() const;

private:
    TriangleSet m_tris;
    ConnectorSet m_conns;
};

typedef std::map<SolutionKey, class SolutionData> SolutionMap;

class SolutionData {
public:
    SolutionData()
      : m_lastPeriIdx(0),
        m_rotAng(0.0f),
        m_xShift(0.0f), m_yShift(0.0f) {
    }

    void init(int triIdx);

    bool fitsInBox();
    bool selfOverlaps() const;

    void nextGeneration(
        const SolutionKey& key, bool useTrim, SolutionMap& rNewSols) const;

    void print() const;

private:
    void addTriangle(
        const SolutionKey& key, int periIdx, int newTriIdx,
        SolutionMap& rNewSols) const;

    std::vector<int> m_periTris;
    std::vector<int> m_periLens;
    std::vector<bool> m_periFlipped;
    std::vector<Vec2> m_periPoints;

    int m_lastPeriIdx;

    std::vector<Vec2> m_triPoints;

    float m_rotAng;
    float m_xShift, m_yShift;
};

static int BoxW  = 0;
static int BoxH  = 0;
static int BoxD2 = 0;

static TriangleVec AllTriangles;
static SideMap AllSides;

Connector::Connector(
    int sideLen, int triIdx1, int triIdx2, bool flipped)
  : m_sideLen(sideLen),
    m_flipped(flipped) {
    if (triIdx1 < triIdx2) {
        m_triIdx1 = triIdx1;
        m_triIdx2 = triIdx2;
    } else {
        m_triIdx1 = triIdx2;
        m_triIdx2 = triIdx1;
    }
}

bool Connector::operator<(const Connector& rhs) const {
    if (m_sideLen < rhs.m_sideLen) {
        return true;
    } else if (m_sideLen > rhs.m_sideLen) {
        return false;
    }

    if (m_triIdx1 < rhs.m_triIdx1) {
        return true;
    } else if (m_triIdx1 > rhs.m_triIdx1) {
        return false;
    }

    if (m_triIdx2 < rhs.m_triIdx2) {
        return true;
    } else if (m_triIdx2 > rhs.m_triIdx2) {
        return false;
    }

    return m_flipped < rhs.m_flipped;
}

void SolutionKey::init(int triIdx) {
    m_tris.insert(triIdx);
}

void SolutionKey::add(int triIdx, const Connector& conn) {
    m_tris.insert(triIdx);
    m_conns.insert(conn);
}

bool SolutionKey::containsTriangle(int triIdx) const {
    return m_tris.count(triIdx);
}

int SolutionKey::minTriangle() const {
    return *m_tris.begin();
}

bool SolutionKey::operator<(const SolutionKey& rhs) const {
    if (m_tris.size() < rhs.m_tris.size()) {
        return true;
    } else if (m_tris.size() > rhs.m_tris.size()) {
        return false;
    }

    TriangleSet::const_iterator triIt1 = m_tris.begin();
    TriangleSet::const_iterator triIt2 = rhs.m_tris.begin();
    while (triIt1 != m_tris.end()) {
        if (*triIt1 < *triIt2) {
           return true;
        } else if (*triIt2 < *triIt1) {
           return false;
        }
        ++triIt1;
        ++triIt2;
    }

    if (m_conns.size() < rhs.m_conns.size()) {
        return true;
    } else if (m_conns.size() > rhs.m_conns.size()) {
        return false;
    }

    ConnectorSet::const_iterator connIt1 = m_conns.begin();
    ConnectorSet::const_iterator connIt2 = rhs.m_conns.begin();
    while (connIt1 != m_conns.end()) {
        if (*connIt1 < *connIt2) {
           return true;
        } else if (*connIt2 < *connIt1) {
           return false;
        }
        ++connIt1;
        ++connIt2;
    }

    return false;
}

void SolutionKey::print() const {
    TriangleSet::const_iterator triIt = m_tris.begin();
    while (triIt != m_tris.end()) {
        std::cout << *triIt << " ";
        ++triIt;
    }
    std::cout << "\n";

    ConnectorSet::const_iterator connIt = m_conns.begin();
    while (connIt != m_conns.end()) {
        connIt->print();
        ++connIt;
    }
    std::cout << "\n";
}

void SolutionData::init(int triIdx) {
    const Triangle& tri = AllTriangles[triIdx];

    m_periTris.push_back(triIdx);
    m_periTris.push_back(triIdx);
    m_periTris.push_back(triIdx);

    m_periLens.push_back(tri.getSideLenB());
    m_periLens.push_back(tri.getSideLenC());
    m_periLens.push_back(tri.getSideLenA());

    m_periFlipped.push_back(false);
    m_periFlipped.push_back(false);
    m_periFlipped.push_back(false);

    m_periPoints.push_back(Vec2(0.0f, 0.0f));
    m_periPoints.push_back(Vec2(tri.getSideLenB(), 0.0f));
    m_periPoints.push_back(Vec2(0.0f, tri.getSideLenA()));

    m_triPoints = m_periPoints;

    m_periPoints.push_back(Vec2(0.0f, 0.0f));
}

bool SolutionData::fitsInBox() {
    int nStep = 8;
    float angInc = 0.5f * M_PI / nStep;

    for (;;) {
        bool mayFit = false;
        float ang = 0.0f;

        for (int iStep = 0; iStep <= nStep; ++iStep) {
            float cosAng = cos(ang);
            float sinAng = sin(ang);

            float xMin = 0.0f;
            float xMax = 0.0f;
            float yMin = 0.0f;
            float yMax = 0.0f;
            bool isFirst = true;

            for (int iPeri = 0; iPeri < m_periLens.size(); ++iPeri) {
                const Vec2& pt = m_periPoints[iPeri];
                float x = cosAng * pt.x() - sinAng * pt.y();
                float y = sinAng * pt.x() + cosAng * pt.y();

                if (isFirst) {
                    xMin = x;
                    xMax = x;
                    yMin = y;
                    yMax = y;
                    isFirst = false;
                } else {
                    if (x < xMin) {
                        xMin = x;
                    } else if (x > xMax) {
                        xMax = x;
                    }
                    if (y < yMin) {
                        yMin = y;
                    } else if (y > yMax) {
                        yMax = y;
                    }
                }
            }

            float w = xMax - xMin;
            float h = yMax - yMin;

            bool fits = false;
            if ((BoxW >= BoxH) == (w >= h)) {
                if (w <= BoxW && h <= BoxH) {
                    m_rotAng = ang;
                    m_xShift = 0.5f * BoxW - 0.5f * (xMax + xMin);
                    m_yShift = 0.5f * BoxH - 0.5f * (yMax + yMin);
                    return true;
                }
            } else {
                if (h <= BoxW && w <= BoxH) {
                    m_rotAng = ang + 0.5f * M_PI;
                    m_xShift = 0.5f * BoxW + 0.5f * (yMax + yMin);
                    m_yShift = 0.5f * BoxH - 0.5f * (xMax + xMin);
                    return true;
                }
            }

            w -= 0.125f * w * angInc * angInc + 0.5f * h * angInc;
            h -= 0.125f * h * angInc * angInc + 0.5f * w * angInc;

            if ((BoxW < BoxH) == (w < h)) {
                if (w <= BoxW && h <= BoxH) {
                    mayFit = true;
                }
            } else {
                if (h <= BoxW && w <= BoxH) {
                    mayFit = true;
                }
            }

            ang += angInc;
        }

        if (!mayFit) {
            break;
        }

        nStep *= 4;
        angInc *= 0.25f;
    }

    return false;
}

static bool intersects(
    const Vec2& p1, const Vec2& p2,
    const Vec2& q1, const Vec2& q2) {

    if (cross(p2 - p1, q1 - p1) * cross(p2 - p1, q2 - p1) > 0.0f) {
        return false;
    }

    if (cross(q2 - q1, p1 - q1) * cross(q2 - q1, p2 - q1) > 0.0f) {
        return false;
    }

    return true;
}

bool SolutionData::selfOverlaps() const {
    int periSize = m_periPoints.size();

    int triIdx = m_periTris[m_lastPeriIdx];
    const Triangle& tri = AllTriangles[triIdx];
    float offsScale = 0.0001f / tri.getSideLenC();

    const Vec2& pt1 = m_periPoints[m_lastPeriIdx];
    const Vec2& pt3 = m_periPoints[m_lastPeriIdx + 1];
    const Vec2& pt2 = m_periPoints[m_lastPeriIdx + 2];

    Vec2 pt1o = pt1 + ((pt2 - pt1) + (pt3 - pt1)) * offsScale;
    Vec2 pt2o = pt2 + ((pt1 - pt2) + (pt3 - pt2)) * offsScale;
    Vec2 pt3o = pt3 + ((pt1 - pt3) + (pt2 - pt3)) * offsScale;

    float xMax = m_periPoints[0].x();
    float yMax = m_periPoints[0].y();
    for (int iPeri = 1; iPeri < m_periLens.size(); ++iPeri) {
        if (m_periPoints[iPeri].x() > xMax) {
            xMax = m_periPoints[iPeri].x();
        }
        if (m_periPoints[iPeri].y() > yMax) {
            yMax = m_periPoints[iPeri].y();
        }
    }

    Vec2 ptOut(xMax + 0.3f, yMax + 0.7f);
    int nOutInter = 0;

    for (int iPeri = 0; iPeri < m_periLens.size(); ++iPeri) {
        int iNextPeri = iPeri + 1;
        if (iPeri == m_lastPeriIdx) {
            ++iNextPeri;
        } else if (iPeri == m_lastPeriIdx + 1) {
            continue;
        }

        if (intersects(
            m_periPoints[iPeri], m_periPoints[iNextPeri], pt1o, pt3o)) {
            return true;
        }

        if (intersects(
            m_periPoints[iPeri], m_periPoints[iNextPeri], pt2o, pt3o)) {
            return true;
        }

        if (intersects(
            m_periPoints[iPeri], m_periPoints[iNextPeri], pt3o, ptOut)) {
            ++nOutInter;
        }
    }

    return nOutInter % 2;
}

void SolutionData::nextGeneration(
    const SolutionKey& key, bool useTrim, SolutionMap& rNewSols) const
{
    int nPeri = m_periLens.size();
    for (int iPeri = (useTrim ? 0 : m_lastPeriIdx); iPeri < nPeri; ++iPeri) {
        int len = m_periLens[iPeri];
        SideMap::const_iterator itCand = AllSides.lower_bound(len);
        SideMap::const_iterator itCandEnd = AllSides.upper_bound(len);
        while (itCand != itCandEnd) {
            int candTriIdx = itCand->second;
            if (!key.containsTriangle(candTriIdx) &&
                candTriIdx > key.minTriangle()) {
                addTriangle(key, iPeri, candTriIdx, rNewSols);
            }
            ++itCand;
        }
    }
}

void SolutionData::print() const {
    float cosAng = cos(m_rotAng);
    float sinAng = sin(m_rotAng);

    int nPoint = m_triPoints.size();

    for (int iPoint = 0; iPoint < nPoint; ++iPoint) {
        const Vec2& pt = m_triPoints[iPoint];
        float x = cosAng * pt.x() - sinAng * pt.y() + m_xShift;
        float y = sinAng * pt.x() + cosAng * pt.y() + m_yShift;
        std::cout << "(" << x << ", " << y << ")";

        if (iPoint % 3 == 2) {
            std::cout << std::endl;
        } else {
            std::cout << " ";
        }
    }
}

void SolutionData::addTriangle(
    const SolutionKey& key, int periIdx, int newTriIdx,
    SolutionMap& rNewSols) const {

    int triIdx = m_periTris[periIdx];
    bool flipped = m_periFlipped[periIdx];
    int len = m_periLens[periIdx];

    Connector conn1(len, triIdx, newTriIdx, flipped);
    SolutionKey newKey1(key);
    newKey1.add(newTriIdx, conn1);
    bool isNew1 = (rNewSols.find(newKey1) == rNewSols.end());

    Connector conn2(len, triIdx, newTriIdx, !flipped);
    SolutionKey newKey2(key);
    newKey2.add(newTriIdx, conn2);
    bool isNew2 = (rNewSols.find(newKey2) == rNewSols.end());

    if (!(isNew1 || isNew2)) {
        return;
    }

    SolutionData data;

    int periSize = m_periLens.size();
    data.m_periTris.resize(periSize + 1);
    data.m_periLens.resize(periSize + 1);
    data.m_periFlipped.resize(periSize + 1);
    data.m_periPoints.resize(periSize + 2);
    for (int k = 0; k <= periIdx; ++k) {
        data.m_periTris[k] = m_periTris[k];
        data.m_periLens[k] = m_periLens[k];
        data.m_periFlipped[k] = m_periFlipped[k];
        data.m_periPoints[k] = m_periPoints[k];
    }
    for (int k = periIdx + 1; k < periSize; ++k) {
        data.m_periTris[k + 1] = m_periTris[k];
        data.m_periLens[k + 1] = m_periLens[k];
        data.m_periFlipped[k + 1] = m_periFlipped[k];
        data.m_periPoints[k + 1] = m_periPoints[k];
    }
    data.m_periPoints[periSize + 1] = m_periPoints[periSize];

    data.m_lastPeriIdx = periIdx;

    data.m_periTris[periIdx] = newTriIdx;
    data.m_periTris[periIdx + 1] = newTriIdx;

    int triSize = m_triPoints.size();
    data.m_triPoints.resize(triSize + 3);
    for (int k = 0; k < triSize; ++k) {
        data.m_triPoints[k] = m_triPoints[k];
    }

    const Triangle& tri = AllTriangles[newTriIdx];
    int lenA = tri.getSideLenA();
    int lenB = tri.getSideLenB();
    int lenC = tri.getSideLenC();

    const Vec2& pt1 = m_periPoints[periIdx];
    const Vec2& pt2 = m_periPoints[periIdx + 1];

    Vec2 v = pt2 - pt1;
    v.normalize();
    Vec2 vn(v.y(), -v.x());

    float dA = lenA;
    float dB = lenB;
    float dC = lenC;

    int len1 = 0, len2 = 0;
    Vec2 pt31, pt32;

    if (len == lenA) {
        len1 = lenB;
        len2 = lenC;
        pt31 = pt1 + vn * dB;
        pt32 = pt2 + vn * dB;
    } else if (len == lenB) {
        len1 = lenC;
        len2 = lenA;
        pt31 = pt2 + vn * dA;
        pt32 = pt1 + vn * dA;
    } else {
        len1 = lenA;
        len2 = lenB;
        pt31 = pt1 + v * (dA * dA / dC) + vn * (dA * dB / dC);
        pt32 = pt1 + v * (dB * dB / dC) + vn * (dA * dB / dC);
    }

    if (isNew1) {
        data.m_periLens[periIdx] = len1;
        data.m_periLens[periIdx + 1] = len2;
        data.m_periFlipped[periIdx] = false;
        data.m_periFlipped[periIdx + 1] = false;
        data.m_periPoints[periIdx + 1] = pt31;

        data.m_triPoints[triSize] = pt1;
        data.m_triPoints[triSize + 1] = pt31;
        data.m_triPoints[triSize + 2] = pt2;

        rNewSols.insert(std::make_pair(newKey1, data));
    }

    if (isNew2) {
        data.m_periLens[periIdx] = len2;
        data.m_periLens[periIdx + 1] = len1;
        data.m_periFlipped[periIdx] = true;
        data.m_periFlipped[periIdx + 1] = true;
        data.m_periPoints[periIdx + 1] = pt32;

        data.m_triPoints[triSize] = pt1;
        data.m_triPoints[triSize + 1] = pt32;
        data.m_triPoints[triSize + 2] = pt2;

        rNewSols.insert(std::make_pair(newKey2, data));
    }
}

static void enumerateTriangles() {
    for (int c = 2; c * c <= BoxD2; ++c) {
        for (int a = 1; 2 * a * a < c * c; ++a) {
            int b = static_cast<int>(sqrt(c * c - a * a) + 0.5f);
            if (a * a + b * b == c * c) {
                Triangle tri(a, b, c);

                int triIdx = AllTriangles.size();
                AllTriangles.push_back(Triangle(a, b, c));

                AllSides.insert(std::make_pair(a, triIdx));
                AllSides.insert(std::make_pair(b, triIdx));
                AllSides.insert(std::make_pair(c, triIdx));
            }
        }
    }
}

static void eliminateInvalid(SolutionMap& rSols) {
    SolutionMap::iterator it = rSols.begin();
    while (it != rSols.end()) {
        SolutionMap::iterator itNext = it;
        ++itNext;

        SolutionData& rSolData = it->second;

        if (!rSolData.fitsInBox()) {
            rSols.erase(it);
        } else if (rSolData.selfOverlaps()) {
            rSols.erase(it);
        }

        it = itNext;
    }
}

static void trimSolutions(SolutionMap& rSols, int trimCount) {
    if (trimCount >= rSols.size()) {
        return;
    }

    SolutionMap::iterator it = rSols.begin();
    for (int iTrim = 0; iTrim < trimCount; ++iTrim) {
        ++it;
    }

    rSols.erase(it, rSols.end());
}

static void nextGeneration(
    const SolutionMap& srcSols, bool useTrim, SolutionMap& rNewSols) {
    SolutionMap::const_iterator it = srcSols.begin();
    while (it != srcSols.end()) {
        const SolutionKey& solKey = it->first;
        const SolutionData& solData = it->second;
        solData.nextGeneration(solKey, useTrim, rNewSols);
        ++it;
    }
}

static void printSolutions(const SolutionMap& sols) {
    std::cout << std::fixed;
    std::cout.precision(3);

    SolutionMap::const_iterator it = sols.begin();
    while (it != sols.end()) {
        const SolutionKey& solKey = it->first;
        solKey.print();
        const SolutionData& solData = it->second;
        solData.print();
        std::cout << std::endl;
        ++it;
    }
}

int main(int argc, char* argv[]) {
    if (argc < 3) {
        std::cerr << "usage: " << argv[0] << " width height [trimCount]"
                  << std::endl;
        return 1;
    }

    std::istringstream streamW(argv[1]);
    streamW >> BoxW;
    std::istringstream streamH(argv[2]);
    streamH >> BoxH;

    int trimCount = 0;
    if (argc > 3) {
        std::istringstream streamTrim(argv[3]);
        streamTrim >> trimCount;
    }

    BoxD2 = BoxW * BoxW + BoxH * BoxH;

    enumerateTriangles();
    int nTri = AllTriangles.size();

    SolutionMap solGen[2];
    int srcGen = 0;

    for (int iTri = 0; iTri < nTri; ++iTri) {
        const Triangle& tri = AllTriangles[iTri];

        SolutionKey solKey;
        solKey.init(iTri);

        SolutionData solData;
        solData.init(iTri);

        solGen[srcGen].insert(std::make_pair(solKey, solData));
    }

    int level = 1;

    for (;;) {
        eliminateInvalid(solGen[srcGen]);
        std::cout << "level: " << level
                  << " solutions: " << solGen[srcGen].size() << std::endl;
        if (solGen[srcGen].empty()) {
            break;
        }

        if (trimCount > 0) {
            trimSolutions(solGen[srcGen], trimCount);
        }

        solGen[1 - srcGen].clear();
        nextGeneration(solGen[srcGen], trimCount > 0, solGen[1 - srcGen]);

        srcGen = 1 - srcGen;
        ++level;
    }

    printSolutions(solGen[1 - srcGen]);

    return 0;
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.