Wythoff 매트릭스 모듈로 2에서 특정 값 인쇄


11

Wythoff 행렬은 Wythoff의 게임 에서 체스 판에있는 각 사각형 의 Grundy 숫자 로 구성된 무한 행렬입니다 입니다.

이 행렬의 각 항목은 항목 위치의 위, 왼쪽 또는 대각선 북서쪽에 나타나지 않는 가장 작은 음수가 아닙니다.

왼쪽 위 20 x 20 사각형은 다음과 같습니다.

  0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19
  1  2  0  4  5  3  7  8  6 10 11  9 13 14 12 16 17 15 19 20
  2  0  1  5  3  4  8  6  7 11  9 10 14 12 13 17 15 16 20 18
  3  4  5  6  2  0  1  9 10 12  8  7 15 11 16 18 14 13 21 17
  4  5  3  2  7  6  9  0  1  8 13 12 11 16 15 10 19 18 17 14
  5  3  4  0  6  8 10  1  2  7 12 14  9 15 17 13 18 11 16 21
  6  7  8  1  9 10  3  4  5 13  0  2 16 17 18 12 20 14 15 11
  7  8  6  9  0  1  4  5  3 14 15 13 17  2 10 19 21 12 22 16
  8  6  7 10  1  2  5  3  4 15 16 17 18  0  9 14 12 19 23 24
  9 10 11 12  8  7 13 14 15 16 17  6 19  5  1  0  2  3  4 22
 10 11  9  8 13 12  0 15 16 17 14 18  7  6  2  3  1  4  5 23
 11  9 10  7 12 14  2 13 17  6 18 15  8 19 20 21  4  5  0  1
 12 13 14 15 11  9 16 17 18 19  7  8 10 20 21 22  6 23  3  5
 13 14 12 11 16 15 17  2  0  5  6 19 20  9  7  8 10 22 24  4
 14 12 13 16 15 17 18 10  9  1  2 20 21  7 11 23 22  8 25 26
 15 16 17 18 10 13 12 19 14  0  3 21 22  8 23 20  9 24  7 27
 16 17 15 14 19 18 20 21 12  2  1  4  6 10 22  9 13 25 11 28
 17 15 16 13 18 11 14 12 19  3  4  5 23 22  8 24 25 21 26 10
 18 19 20 21 17 16 15 22 23  4  5  0  3 24 25  7 11 26 12 13
 19 20 18 17 14 21 11 16 24 22 23  1  5  4 26 27 28 10 13 25

Wythoff 매트릭스에서 임의의 엔트리를 계산하기위한 효율적인 알고리즘은 현재 알려져 있지 않다. 그러나이 문제의 임무는 특정 좌표의 숫자인지 여부를 알려주는 휴리스틱 함수를 디자인하는 것입니다.wythoff(x, y) 가 짝수인지 홀수 입니다.

프로그램에 64KB (65,536 바이트) 이상의 소스 코드가 포함되어 있지 않거나 2MB (2,097,152 바이트) 이상의 작업 메모리가 사용될 수 있습니다.

특히 메모리 사용의 경우 이는 프로그램의 최대 상주 세트 크기가 해당 언어의 빈 프로그램의 최대 상주 세트 크기보다 2MB를 초과 할 수 없음을 의미합니다. 해석 된 언어의 경우 인터프리터 / 가상 시스템 자체의 메모리 사용량이되고 컴파일 된 언어의 경우 기본 메소드를 실행하고 아무 것도 수행하지 않는 프로그램의 메모리 사용량이됩니다.

프로그램은의 10000 x 10000행 값 20000 <= x <= 29999과 열 값 에 대해 매트릭스에서 테스트됩니다 20000 <= y <= 29999.

프로그램의 점수는 프로그램이 달성하는 정확도 (정확한 추측 횟수)이며 짧은 코드는 순위 결정 역할을합니다.


3
01.R무작위로 true 또는 false를 출력하는 05AB1E입니다. 0은 true이고 1은 false입니다. 내 프로그램은 이론적으로 ~ 50 %의 시간이 정확합니다. 유효한 항목입니까?
— 매직 문어 Urn

@carusocomputing 실제로, 무작위 솔루션은 허용되지 않는다는 것을 언급하지 않았습니다 . 워드 함수가 의미하는 것으로 생각되지만 프로그램은 매번 동일한 입력에 대해 동일한 출력을 생성해야 합니다.
— Joe Z.

각 호출에서 내 prng의 시드를 수정하면 동일한 입력에 대해 동일한 출력이 생성되며 의미가 무엇인지 알지만 어떻게 든 더 구체적으로 말해야 할 것입니다.
— 마일


@Linus "Wythoff의 게임 매트릭스"가 더 좋을까요? 나는 그 페이지도 보았다.
— Joe Z.

답변:


6

파이썬; 정확도 = 54,074,818; 크기 = 65,526 바이트

이전 점수 : 50,227,165; 50,803,687; 50,953,001

#coding=utf-8
d=r'''<65,400 byte string>'''
def f(x,y):
 a=max(x,y)-20000;b=min(x,y)-20000;c=(a*(a+1)//2+b)%523200
 return(ord(d[c//8])>>(c%8))&1

이 방법은 행렬의 모든 고유 항목을 523,200 개의 그룹으로 나누고 이진 문자열에서 그룹 (x, y)에 대한 최상의 추측을 읽습니다 . Google 드라이브 에서 전체 소스 코드를 다운로드 할 수 있습니다 .

내가 사용했습니다 PeterTaylor의 패리티 @ 문자열을 생성하고 정확도를 계산하기.


나는 여러 가지 더 흥미로운 접근 방식을 시도했지만 결국에는 간단한 하드 코드가 모든 것을 능가했습니다.
— Dennis

하드 코딩도 유효한 접근 방식입니다. 예를 들어 어떤 하드 코딩 체계가 최상의 결과를 반환 할 수 있습니다.
— Joe Z.

달리 말하지는 않지만, 패리티의 분포는 분명히 무작위가 아니기 때문에 나는이 접근법을 과시하기를 바랐다. 지금까지 나의 모든 시도는 실패했습니다.
— Dennis

아냐 괜찮아 그것은 단지이 문제가 너무 어렵다는 것을 의미합니다. 나는 1 차원을 제외하고이 스타일에 대해 더 많은 문제를 만들어 왔습니다. 체크 아웃하려면 모두 샌드 박스에 있습니다.
— Joe Z.

4

CJam (정확도 50016828/100000000, 6 바이트)

{+1&!}

(CJammer 이외의 경우 ALGOL 스타일 의사 코드 :) return ((x + y) & 1) == 0.

이것은 내가 시도한 다른 24 가지 간단한 휴리스틱 중 하나보다 우수합니다. 다음 두 가지 최고의 조합과 비교하면 훨씬 좋습니다.


점수는 계산 된 행렬 섹션이 정확하다고 가정합니다. 독립적 인 확인을 환영합니다. http://cheddarmonk.org/codegolf/PPCG95604-parity.bz2 에서 계산 된 패리티 비트를 호스팅하고 있습니다 . (8MB 다운로드, 50MB 텍스트 파일로 추출 : 매트릭스는 기본 대각선에 대해 대칭이므로 각 블록 만 포함했습니다 주 대각선에서 시작하므로 전체 정사각형을 얻으려면 오프셋, 조옮김 및 비트 OR을 사용해야합니다.

내가 계산하는 데 사용한 코드는 Java입니다. 정의를 매우 간단하게 사용하지만 실행 길이를 인코딩하는 세트 데이터 구조를 사용하여 다음 허용 값으로 빠르게 건너 뛸 수 있습니다. 추가 최적화가 가능하지만 약 2 시간 및 1.5GB의 힙 공간에서 적당히 오래된 데스크탑에서 실행됩니다.

import java.util.*;

public class PPCG95604Analysis
{
    static final int N = 30000;

    public static void main(String[] args) {
        Indicator[] cols = new Indicator[N];
        Indicator[] diag = new Indicator[N];
        for (int i = 0; i < N; i++) {
            cols[i] = new Indicator();
            diag[i] = new Indicator();
        }

        int maxVal = 0;

        for (int y = 0; y < N; y++) {
            Indicator row = new Indicator(cols[y]);

            for (int x = y; x < N; x++) {
                Indicator col = cols[x];
                Indicator dia = diag[x - y];

                Indicator.Result rr = row.firstCandidate();
                Indicator.Result rc = col.firstCandidate();
                Indicator.Result rd = dia.firstCandidate();

                while (true) {
                    int max = Math.max(Math.max(rr.candidateValue(), rc.candidateValue()), rd.candidateValue());
                    if (rr.candidateValue() == max && rc.candidateValue() == max && rd.candidateValue() == max) break;

                    if (rr.candidateValue() != max) rr = rr.firstCandidateGreaterThan(max - 1);
                    if (rc.candidateValue() != max) rc = rc.firstCandidateGreaterThan(max - 1);
                    if (rd.candidateValue() != max) rd = rd.firstCandidateGreaterThan(max - 1);
                }

                if (y >= 20000 && x >= 20000) System.out.format("%d", rr.candidateValue() & 1);
                maxVal = Math.max(maxVal, rr.candidateValue());
                rr.markUsed();
                rc.markUsed();
                rd.markUsed();
            }
            if (y >= 20000) System.out.println();
        }
    }

    static class Indicator
    {
        private final int INFINITY = (short)0xffff;
        private final int MEMBOUND = 10000;

        private short[] runLengths = new short[MEMBOUND];

        public Indicator() { runLengths[1] = INFINITY; }

        public Indicator(Indicator clone) { System.arraycopy(clone.runLengths, 0, runLengths, 0, MEMBOUND); }

        public Result firstCandidate() {
            // We have a run of used values, followed by a run of unused ones.
            return new Result(1, 0xffff & runLengths[0], 0xffff & runLengths[0]);
        }

        class Result
        {
            private final int runIdx;
            private final int runStart;
            private final int candidateValue;

            Result(int runIdx, int runStart, int candidateValue) {
                this.runIdx = runIdx;
                this.runStart = runStart;
                this.candidateValue = candidateValue;
            }

            public int candidateValue() {
                return candidateValue;
            }

            public Result firstCandidateGreaterThan(int x) {
                if (x < candidateValue) throw new IndexOutOfBoundsException();

                int idx = runIdx;
                int start = runStart;
                while (true) {
                    int end = start + (0xffff & runLengths[idx]) - 1;
                    if (end > x) return new Result(idx, start, x + 1);

                    // Run of excluded
                    start += 0xffff & runLengths[idx];
                    idx++;
                    // Run of included
                    start += 0xffff & runLengths[idx];
                    idx++;

                    if (start > x) return new Result(idx, start, start);
                }
            }

            public void markUsed() {
                if (candidateValue == runStart) {
                    // Transfer one from the start of the run to the previous run
                    runLengths[runIdx - 1]++;
                    if (runLengths[runIdx] != INFINITY) runLengths[runIdx]--;
                    // May need to merge runs
                    if (runLengths[runIdx] == 0) {
                        runLengths[runIdx - 1] += runLengths[runIdx + 1];
                        for (int idx = runIdx; idx < MEMBOUND - 2; idx++) {
                            runLengths[idx] = runLengths[idx + 2];
                            if (runLengths[idx] == INFINITY) break;
                        }
                    }

                    return;
                }

                if (candidateValue == runStart + (0xffff & runLengths[runIdx]) - 1) {
                    // Transfer one from the end of the run to the following run.
                    if (runLengths[runIdx + 1] != INFINITY) runLengths[runIdx + 1]++;
                    if (runLengths[runIdx] != INFINITY) runLengths[runIdx]--;
                    // We never need to merge runs, because if we did we'd have hit the previous case instead
                    return;
                }

                // Need to split the run. From
                //   runIdx: a+1+b
                // to
                //   runIdx: a
                //   runIdx+1: 1
                //   runIdx+2: b
                //   runIdx+3: previous val at runIdx+1
                for (int idx = MEMBOUND - 1; idx > runIdx + 2; idx--) {
                    runLengths[idx] = runLengths[idx - 2];
                }
                runLengths[runIdx + 2] = runLengths[runIdx] == INFINITY ? INFINITY : (short)((0xffff & runLengths[runIdx]) + runStart - 1 - candidateValue);
                runLengths[runIdx + 1] = 1;
                runLengths[runIdx] = (short)(candidateValue - runStart);
            }
        }
    }
}

3

J, 정확도 = 50022668/10 8 = 50.0227 %, 4 바이트

2|*.

좌표를 두 개의 인수로 취하고 그 사이의 LCM을 계산하여 모듈로 2를 취합니다. A 0 .1 수단은 홀수이다.

성능은 @에서 제공하는 패리티 비트를 기반으로합니다. Peter Taylor가 .

7 바이트 이전의 PRNG 버전 2|?.@#. 10분의 50,010,491의 정확도했다 (8) 입니다.

설명

2|*.  Input: x on LHS, y on RHS
  *.  LCM(x, y)
2|    Modulo 2

1
LCM의 패리티는 비트 AND의 패리티입니다. 바이트를 절약합니까? 매혹적인 것은 휴리스틱이 너무 나쁘다는 것입니다 ( 1정확한 비율이 거의 정확히 50 % 일 때 시간의 25 % 만 제공 함 ). 그러나 그렇게 나쁘지 않은 많은 것보다 낫습니다.
— Peter Taylor

고맙지 만 불행히도 J의 AND는 문자 그대로 AND입니다.
— 마일

@PeterTaylor 놀랄만 한 휴리스틱 발견은 이런 도전에 관한 것입니다.
— Joe Z.
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.