삼각형을 잃지 않고 삼각형 배열에서 점 제거


17

나는이 조합론 문제 내가 입고 싶은 것을 OEIS을 -THE 문제는 내가 충분히 용어를 필요가 없다는 것입니다. 이 코드 문제는 더 많은 용어를 계산하는 데 도움이되며 가장 많은 수의 용어를 포함하는 제출물을 가진 사용자가 승자가됩니다.


문제

측면 길이가 삼각형 전구 배열을 제공한다고 가정 해보십시오 .n

     o
    o o
   o o o
  o o o o
 o o o o o
o o o o o o
1 2  ...  n

다음 예와 같이 "똑바로"정삼각형을 이루는 세 개의 전구를 켜겠습니다.

     o
    o x
   o o o
  o o o o
 o x o o x
o o o o o o

조명을 켜기 전에, 켜진 전구의 삼각형을 추론하는 능력을 잃지 않으면 서 어레이에서 가능한 많은 전구를 제거해야합니다. 분명히, 전구가 제거 된 경우 위치를 켤 때 불이 켜지지 않습니다.

예를 들어, 다음 전구 (으로 표시 .) 를 제거하면 다음 두 표시등 만 켜집니다 (로 표시됨 x). 이는 세 번째 ( 점등 되지 않은) 위치를 고유하게 추론 할 수 있습니다.

     .              .
    . o            . x
   . . o          . . o
  o o o .   =>   o o o .
 o o o o .      o x o o . <- the third unlit position
o . . . o o    o . . . o o

a(n)모호성을 유발하지 않고 제거 할 수있는 최대 전구 수를 보자 .


순진한 알고리즘을 사용하여 아래와 같이 측면 길이 7의 삼각형까지 값을 확인했습니다.

                                                                      .
                                                      .              . o
                                        .            . o            o . o
                           .           . .          . . o          . o o .
              .           . .         . o o        o o o .        o o . o .
 .           . .         . o o       o o . o      o o o o .      o . o . o o
. .         . o o       . o o o     o . . o o    o . . . o o    o . o . o o o

a(2) = 3    a(3) = 4    a(4) = 5    a(5) = 7     a(6) = 9       a(7) = 11

채점

시퀀스를 계산하는 제출 [a(2), a(3), ..., a(n)]최대 n 개의 를 이깁니다. 두 제출물에 동일한 순서가있는 경우 이전에 게시 된 제출물이 우선합니다.

제출에는 필요하지 않지만 위의 예와 같이 결과 삼각 삼각 배열의 구성을 게시하면 도움이 될 것입니다.


1
이것이 가장 빠른 코드가 아니라 코드 도전이 아닌가?
Don Thousand

6
컨테스트가 누군가가 코드를 실행하는 데 걸린 시간이 아니도록 시간 제한 (60 초)을 선택해야한다고 생각합니다.
dylnan

좋은 문제입니다. "똑바로"삼각형은 무엇을 의미합니까?
Damien

답변:


10

파이썬 3 ,n=8

import itertools
from ortools.sat.python import cp_model


def solve(n):
    model = cp_model.CpModel()
    solver = cp_model.CpSolver()
    cells = {
        (y, x): model.NewBoolVar(str((y, x)))
        for y in range(n) for x in range(y + 1)}
    triangles = [
            {cells[v] for v in ((y1, x1), (y2, x1), (y2, x1 + y2 - y1))}
            for (y1, x1) in cells.keys() for y2 in range(y1 + 1, n)]
    for t1, t2 in itertools.combinations(triangles, 2):
        model.AddBoolOr(t1.symmetric_difference(t2))
    model.Minimize(sum(cells.values()))
    solver.Solve(model)
    return len(cells) - round(solver.ObjectiveValue())


for n in itertools.count(2):
    print('a(%d) = %d' % (n, solve(n)))

사용 구글 OR-도구 'CP-SAT 해결사.

~ 30 초 동안 실행 한 후 다음을 출력합니다.

a(2) = 3
a(3) = 4
a(4) = 5
a(5) = 7
a(6) = 9
a(7) = 11
a(8) = 13

나는 n=9아마도 몇 시간이 걸리기 때문에 기다리려고하지 않았습니다 (제약 조건 수가 처럼 커짐 )n6 . 30 분 미만의 계산 후에 나는 그것을 알아 냈다 a(9)=15. n=8현재 시간 제약이 불분명하지만 30 분이 너무 길기 때문에 점수를 남기지 않습니다.

작동 원리

두 개의 별개의 정삼각형 과 취하십시오 . 모호성을 피하기 위해 정점에는 정확히 과 중 하나에 속하는 전구가 하나 이상 있어야합니다 .T 2 T 1 T 2T1T2T1T2

따라서이 질문은 모든 삼각형 쌍에 대해 하나의 제약 조건으로 SAT 문제로 표현 될 수 있습니다.

추신 :에 대한 예를 많이 포함하고 n=8싶지만 SAT 솔버에 문제가있어 솔루션을 모두 자체적으로 유지하려고합니다.


솔루션을 Mathematica이식 하기로 결정했습니다 . 불행히도 느립니다.
user202729

2

@ Delfad0r의 프로그램에서 솔루션 얻기

@ Delfad0r의 프로그램을 출력 솔루션으로 확장했습니다. 또한 중간 결과를 제공하므로 다음과 같이 출력됩니다.

Solving n = 8:
a(8) >= 9
a(8) >= 10
a(8) >= 11
a(8) >= 12
a(8) >= 13
       o
      . o
     . o o
    . o o .
   o o . o o
  o o o o . .
 o . . o o o .
o . . o . o o o
a(8) = 13

Solving n = 9:
a(9) >= 10
a(9) >= 13
a(9) >= 14
a(9) >= 15
        o
       o o
      o . .
     o . o o
    . o . o o
   . o o o o o
  o o o . o . .
 o o o . . . o o
. o o o o o o . .
a(9) = 15

이 계산에는 몇 시간이 걸렸습니다.

Ctrl-C최적이 아닌 솔루션을 찾은 후 참을성이 없어지고 압박 을 가하면 프로그램에 해당 솔루션이 표시됩니다. 따라서 이것을 얻는 데 시간이 오래 걸리지 않습니다.

                   .
                  o o
                 . o o
                . o o o
               o o . o o
              o . o o o .
             o . o . o o o
            . o o o o o . o
           o . . o o o o o o
          o o o o o o o o o .
         o o . o o o o . o o o
        o o o o o o . o . o o o
       o . o o . o o o o o o o o
      o o o . o o o o o . o o o o
     o o o . o o o o o o o o . . o
    o o o o o o o o o o o . o . . o
   o o o o . o o o o . o o o o o . o
  o o o o o o o o . o o . . o o o o .
 o o o o . o o . o . o o o o o o . o o
o o . o o . o o o o . o o o . o o o o o
a(20) >= 42

확장 프로그램은 다음과 같습니다.

import itertools
from ortools.sat.python import cp_model

class ReportPrinter(cp_model.CpSolverSolutionCallback):

    def __init__(self, n, total):
        cp_model.CpSolverSolutionCallback.__init__(self)
        self.__n = n
        self.__total = total

    def on_solution_callback(self):
        print('a(%d) >= %d' %
              (self.__n, self.__total-self.ObjectiveValue()) )

def solve(n):
    model = cp_model.CpModel()
    solver = cp_model.CpSolver()
    cells = {
        (y, x): model.NewBoolVar(str((y, x)))
        for y in range(n) for x in range(y + 1)}
    triangles = [
            {cells[v] for v in ((y1, x1), (y2, x1), (y2, x1 + y2 - y1))}
            for (y1, x1) in cells.keys() for y2 in range(y1 + 1, n)]
    for t1, t2 in itertools.combinations(triangles, 2):
        model.AddBoolOr(t1.symmetric_difference(t2))
    model.Minimize(sum(cells.values()))
    print('Solving n = %d:' % n)
    status = solver.SolveWithSolutionCallback(model, ReportPrinter(n,len(cells)))
    if status == cp_model.OPTIMAL:
        rel = '='
    elif status == cp_model.FEASIBLE:
        rel = '>='
    else:
        print('No result for a(%d)\n' % n)
        return
    for y in range(n):
        print(' '*(n-y-1), end='')
        for x in range(y+1):
            print('.o'[solver.Value(cells[(y,x)])],end=' ')
        print()
    print('a(%d) %s %d' % (n, rel, len(cells) - solver.ObjectiveValue()))
    print()

for n in itertools.count(2):
    solve(n)

1

파이썬 3

Delfad0r의 답변 에 강력하게 근거 하여 삼각형 쌍을 확인 하고이 유효성 검사에 실패한 삼각형 쌍이 포함되어 있지 않은 경우 구성의 유효성을 검사하여 동일한 논리 진행을 따릅니다. itertools 및 copy 이외의 라이브러리를 사용하지 않았으므로 프로그램 전체에서 발생하는 예제 저장을 완전히 제어 할 수 있습니다.

examples = dict() # stores examples by key pair of n to a tuple with the triangle and number of lights turned off

for n in range(3, 8):
    tri = [] # model of the triangle, to be filled with booleans representing lights
    tri_points = [] # list of tuples representing points of the triangle
    for i in range(n):
        tri.append([True]*(i + 1))
        for j in range(i+1):
            tri_points.append((i, j))

    t_set = [] # list of all possible triangles from tri, represented by lists of points
    for i in range(n):
        for j in range(len(tri[i])):
            for k in range(1, n - i):
                t_set.append([(i, j), (i + k, j), (i + k, j + k)])

    from itertools import combinations
    import copy

    # validates whether or not a triangle of n lights can have i lights turned off, and saves an example to examples if validated
    def tri_validate(x):
        candidate_list = list(combinations(tri_points, x))
        tri_pairs = list(combinations(t_set, 2))
        for candidate in candidate_list:
            temp_tri = copy.deepcopy(tri)
            valid = False
            for point in candidate:
                (row, col) = point
                temp_tri[row][col] = False
            for pair in tri_pairs:
                valid = False
                (tri1, tri2) = pair
                for point in tri1:
                    if not valid:
                        if point not in tri2:
                            (row, col) = point
                            if temp_tri[row][col]:
                                valid = True
                for point in tri2:
                    if not valid:
                        if point not in tri1:
                            (row, col) = point
                            if temp_tri[row][col]:
                                valid = True
                if not valid:
                    break
            if valid:
                examples[n] = (temp_tri, x)
                return True
        return False

    # iterates up to the point that validation fails, then moves on to the next n
    for i in range(len(tri_points)):
        if tri_validate(i + 1):
            continue
        break

문제는 매우 효율적이지 않다는 것입니다. 실제로 최대 속도로 실행 n=5되지만 해당 지점을 지나서 상당히 느려지기 시작합니다. 에서 n=6실행하는 데 약 1 분이 걸리며에서 속도가 훨씬 느립니다 n=7. 이 프로그램으로 많은 효율성 수정을 할 수 있다고 생각하지만,이 방법의 내부 작업을 확인하는 데 훨씬 더 융통성이있는 훌륭한 솔루션을 신속하게 작성합니다. 시간이 지남에 따라 점진적으로 노력하겠습니다.

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