พิมพ์ค่าเฉพาะใน Wythoff matrix modulo 2


11

Wythoff เมทริกซ์เป็นเมทริกซ์อนันต์ประกอบด้วยหมายเลขใจแคบของแต่ละตารางบนกระดานหมากรุกในเกม Wythoff ของ

แต่ละรายการในเมทริกซ์นี้เท่ากับจำนวน nonnegative ที่เล็กที่สุดซึ่งไม่ปรากฏที่ใดก็ได้ด้านบนไปทางซ้ายหรือทิศตะวันตกเฉียงเหนือของแนวทแยงมุมของตำแหน่งของรายการ

สี่เหลี่ยมจัตุรัสขนาด 20 คูณ 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)นั้นเป็นเลขคู่หรือคี่

โปรแกรมของคุณต้องมีซอร์สโค้ดไม่เกิน 64 KB (65,536 ไบต์) หรือใช้หน่วยความจำที่ใช้งานมากกว่า 2 MB (2,097,152 bytes)

โดยเฉพาะอย่างยิ่งสำหรับการใช้หน่วยความจำหมายความว่าขนาดสูงสุดของชุดที่อยู่อาศัยของโปรแกรมของคุณต้องไม่เกิน 2 MB มากกว่าขนาดสูงสุดของชุดที่อยู่อาศัยของโปรแกรมที่ว่างเปล่าในภาษานั้น ในกรณีของภาษาที่ถูกตีความมันจะเป็นการใช้หน่วยความจำของเครื่องแปลภาษา / เสมือนจริงและในกรณีของภาษาที่รวบรวมมันจะเป็นการใช้หน่วยความจำของโปรแกรมที่ดำเนินการวิธีการหลักและไม่ทำอะไรเลย

โปรแกรมของคุณจะได้รับการทดสอบบน10000 x 10000เมทริกซ์สำหรับค่าแถวในและค่านิยมในคอลัมน์20000 <= x <= 2999920000 <= y <= 29999

คะแนนของโปรแกรมของคุณคืออัตราความถูกต้อง (จำนวนการเดาที่ถูกต้อง) โปรแกรมของคุณประสบความสำเร็จโดยใช้รหัสที่สั้นกว่าทำหน้าที่เป็น tiebreaker


3
01.Rเป็น 05AB1E ที่ให้ผลเป็นสุ่มหรือเท็จ ให้ 0 เป็นจริงและ 1 เป็นเท็จโปรแกรมของฉันในทางทฤษฎีจะถูกต้อง ~ 50% ของเวลา นี่เป็นรายการที่ถูกต้องหรือไม่?
Magic Octopus Urn

@carusocomputing จริง ๆ แล้วฉันลืมที่จะพูดถึงว่าไม่อนุญาตให้ใช้วิธีการแก้ปัญหาแบบสุ่ม - โปรแกรมของคุณควรสร้างผลลัพธ์เดียวกันสำหรับอินพุตเดียวกันทุกครั้งแม้ว่าฉันจะสงสัยว่าฟังก์ชั่นของคำนั้นมีความหมายว่า
Joe Z.

ถ้าฉันแก้ไขเมล็ดของ prng ของฉันในการโทรแต่ละครั้งมันจะสร้างเอาต์พุตเดียวกันสำหรับอินพุตที่เหมือนกันและฉันรู้ว่าคุณหมายถึงอะไร
ไมล์

ฉันได้รับสิ่งที่แตกต่างกันมากเมื่อฉันค้นหาWythoff Matrix
Linus

@Lusus "Game Matrix ของ Wythoff" ดีกว่าไหม ฉันเห็นหน้านั้นด้วย
Joe Z.

คำตอบ:


6

งูหลาม; ความแม่นยำ = 54,074,818; ขนาด = 65,526 ไบต์

คะแนนก่อนหน้า: 50,227,165; 50803687; 50953001

#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 ไดรฟ์

ฉันใช้parities ของ @ PeterTaylorเพื่อสร้างสตริงและคำนวณความถูกต้อง


ฉันลองวิธีที่แตกต่างและน่าสนใจมากกว่าเดิม แต่สุดท้ายแล้ว hardcode ธรรมดา ๆ ก็ให้คะแนนทั้งหมดของพวกเขา ...
Dennis

Hardcoding เป็นวิธีการที่ถูกต้องเช่นกันซึ่งอาจเปลี่ยนเป็นรูปแบบการเข้ารหัสที่ส่งคืนผลลัพธ์ที่ดีที่สุด
Joe Z.

ไม่ได้พูดเป็นอย่างอื่น แต่เนื่องจากการกระจายตัวของ parities นั้นชัดเจนมากไม่ใช่แบบสุ่มฉันจึงหวังว่าจะได้คะแนนมากกว่าวิธีนี้ จนถึงตอนนี้ความพยายามทั้งหมดของฉันล้มเหลว
Dennis

ไม่เป็นไร หมายความว่าปัญหานี้ยากที่จะทำอย่างถูกต้อง ฉันสร้างปัญหาให้กับสไตล์นี้มากขึ้นยกเว้นในมิติเดียว พวกเขาทั้งหมดอยู่ในแซนด์บ็อกซ์ถ้าคุณต้องการตรวจสอบพวกเขา
Joe Z.

4

CJam (ความแม่นยำ 50016828/100000000, 6 ไบต์)

{+1&!}

(pseudocode ใน ALGOL สไตล์สำหรับผู้ที่ไม่ใช่ CJammers: return ((x + y) & 1) == 0)

มันทำงานได้ดีกว่าฮิวริสติกแบบเรียบง่ายอีกสองโหลที่ฉันได้ลอง มันจะดีกว่าการรวมกันกับสองที่ดีที่สุดถัดไป


คะแนนถือว่าส่วนที่คำนวณได้ของเมทริกซ์นั้นถูกต้อง ยินดีตรวจสอบอิสระ ฉันกำลังโฮสต์บิตพาริตีที่คำนวณได้ที่http://cheddarmonk.org/codegolf/PPCG95604-parity.bz2 (ดาวน์โหลด 8MB, แยกเป็นไฟล์ข้อความ 50MB: เนื่องจากเมทริกซ์นั้นสมมาตรกับเส้นทแยงมุมหลักฉันจึงรวมเฉพาะ เส้นที่เริ่มต้นจากเส้นทแยงมุมหลักดังนั้นคุณต้องออฟเซ็ตย้ายและบิตหรือเพื่อให้ได้ตารางเต็ม)

รหัสที่ฉันใช้คำนวณมันคือ Java มันใช้คำจำกัดความค่อนข้างตรงไปตรงมา แต่ด้วยโครงสร้างข้อมูลชุดที่รันความยาวเข้ารหัสช่วงเพื่อให้มันรวดเร็วข้ามไปยังค่าที่ได้รับอนุญาตต่อไป การปรับให้เหมาะสมเพิ่มเติมอาจเป็นไปได้ แต่มันจะรันบนเดสก์ท็อปเก่าปานกลางในประมาณสองชั่วโมงและพื้นที่ว่าง 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 มา0ใช้1หมายความว่ามันเป็นเลขคู่และหมายความว่ามันเป็นเลขคี่

ประสิทธิภาพขึ้นอยู่กับบิตพาริตี้ที่ได้รับจาก @ปีเตอร์เทย์เลอร์

รุ่น PRNG ก่อนหน้า 7 ไบต์ 2|?.@#.มีความถูกต้องของ 50010491/10 8

คำอธิบาย

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

1
ความเท่าเทียมกันของ LCM คือความเท่าเทียมกันของค่าบิตและ นั่นช่วยให้คุณประหยัดไบต์ได้ไหม? สิ่งที่น่าสนใจก็คือมันเป็นวิธีแก้ปัญหาที่ไม่ดีอย่างเห็นได้ชัด (ให้125% ของเวลาเมื่อสัดส่วนที่ถูกต้องเกือบ 50%) แต่ก็ทำได้ดีกว่าหลายอย่างที่ไม่เลวอย่างเห็นได้ชัด
Peter Taylor

ขอบคุณ แต่โชคร้ายบิตและ J ANDเป็นตัวอักษร
ไมล์

@PeterTaylor การค้นพบฮิวริสติกแบบนี้เป็นสิ่งที่ท้าทายอย่างที่ควรจะเป็น
Joe Z.
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.