จำนวนการเอียงที่แตกต่างของจตุรัส n X n พร้อมโพลิโอโนเมียฟรี


17

ลำดับ OEIS "nice"ใหม่ล่าสุดA328020เพิ่งเผยแพร่ไม่กี่นาทีที่ผ่านมา

จำนวนการเอียงที่แตกต่างของจตุรัส n X n พร้อมโพลิโอโนเมียฟรี

ลำดับนี้นับการเอียงขึ้นอยู่กับสมมาตรของจตุรัส ลำดับมีหกคำ แต่ฉันต้องการดูว่าคนที่นี่สามารถขยายได้อีกหรือไม่

ตัวอย่าง

เพราะn=4มี 22 กริดดังที่แสดงในภาพนี้จาก OEIS เครดิต: Jeff Bowermaster, ภาพประกอบ A328020 (4)A328020 (4)

ท้าทาย

เช่นเดียวกับความท้าทายที่ผ่านมาเป้าหมายของความท้าทายนี้คือการคำนวณเงื่อนไขให้มากที่สุดเท่าที่จะเป็นไปได้ในลำดับนี้ซึ่งเริ่มต้นขึ้น1, 1, 2, 22, 515, 56734และที่ใดที่คำที่ n-th เป็นจำนวนการเอียงของกริด n x n กับ n-polyominoes

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


3
นี่คือสมมาตรแบบโมดูโลของจตุรัส?
Peter Taylor

@PeterTaylor ถูกต้องแล้ว ฉันสงสัยในคำถามนี้แล้ว
Peter Kagey

อย่างไร้เดียงสาฉันจะบอกว่ารายการ n'th จะใช้การดำเนินงานnumber_of_fixed_n_polyominoes ^ ( n -1) ในการคำนวณ ดังนั้นสำหรับ n = 7 นั่นจะใช้การดำเนินการ 760 ^ 6 ≈ 2 ^ 57.4 คุณอาจจะลดจำนวนลงได้ แต่มันเป็นจำนวนมากที่จะเริ่มต้นด้วย ...
G. Sliepen

@Sliepen ฉันคาดหวังว่าคุณสามารถลดมันลงได้มากโดยการย้อนรอย โดยเฉพาะอย่างยิ่งมีจำนวนมากของพหุนามคงที่ไม่สามารถวางไว้ในมุมและครั้งหนึ่งเคยเป็น polyomino ที่ถูกต้องจะถูกวางไว้ที่ใดที่หนึ่งก็อย่างมหาศาล constrains สิ่งที่สามารถจะอยู่ติดกับมัน
Peter Kagey

@PeterKagey คุณพูดถูก ฉันคิดว่ามันช่วยถ้าหากคุณได้วาง m-polyominoes ไว้แล้วคุณเลือกตำแหน่งถัดไปเพื่อพยายามวางโพลีโนมิโนในตำแหน่งที่แย่ที่สุดที่เป็นไปได้ซึ่งคุณสามารถตัดมันได้มาก
G. Sliepen

คำตอบ:


9

ส่วนขยายของรหัส @ Grimy รับ N = 8

นี่เป็นการขีดเส้นใต้ที่ @Grimy สมควรได้รับความโปรดปราน:

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

บนเครื่องที่โค้ดต้นฉบับใช้เวลา 2m11s สำหรับ N = 7 จะใช้เวลา 1m4s และคำนวณ N = 8 ใน 33h46m ผลลัพธ์ที่ได้คือ 23437350133

นี่คือการเพิ่มของฉันเป็น diff:

--- tilepoly.c  2019-10-11 12:37:49.676351878 +0200
+++ tilepolyprune.c     2019-10-13 04:28:30.518736188 +0200
@@ -51,6 +51,30 @@
     return 1;
 } 

+static int check_component_sizes(u64 occupied, u64 total){
+    u64 queue[N*N];
+    while (total<N*N){
+        u64 count = 1;
+        u64 start = ctz(~occupied);
+        queue[0] = start;
+        occupied |= 1ul << start;
+        for(u64 current=0; current<count; ++current){
+            u64 free_adjacent = adjacency_matrix[queue[current]] & ~occupied;
+            occupied |= free_adjacent;
+            while (free_adjacent){
+                u64 next = ctz(free_adjacent);
+                free_adjacent &= ~(1ul << next);
+                queue[count++] = next;
+            }
+        }
+        if (count % N){
+            return 0;
+        }
+        total += count;
+    }
+    return 1;
+}
+
 static void recurse(u64 mino, u64 cell, u64 occupied, u64 adjacent, u64 forbidden)
 {
     if (cell >= N) {
@@ -61,6 +85,9 @@
             return;
         }

+        if(!check_component_sizes(occupied,N*mino))
+            return;
+
         u64 next = ctz(~occupied);
         board[next] = mino;
         recurse(mino, 1, occupied | 1ul << next, adjacency_matrix[next], 0);

ลองออนไลน์!


นี่เป็นสิ่งที่ดีมาก
Anush

ทั้งหมดที่เราต้องการตอนนี้คือรุ่น SIMD มัลติเธรด :)
Anush

1
โอ้ช่างยอดเยี่ยมจริงๆ! ฉันคิดว่าการเพิ่มประสิทธิภาพนี้จริง ๆ แต่ไม่คิดว่ามันจะเพียงพอที่จะไปถึง N = 8 ในเวลาที่เหมาะสมดังนั้นฉันจึงไม่ได้กังวลที่จะนำไปใช้
Grimmy

14

C, 7 ข้อกำหนด

คำที่เจ็ดเป็น19846102 (หกตัวแรกคือ 1, 1, 2, 22, 515, 56734 ตามที่ระบุในคำถาม)

#include <stdio.h>
#include <string.h>
#include <stdint.h>

#define N 7
#define ctz __builtin_ctzl

typedef uint64_t u64;

static u64 board[N*N] = { 0 };
static u64 adjacency_matrix[N*N] = { 0 };
static u64 count = 0;

static u64 check_symmetry()
{
    static const u64 symmetries[7][3] = {
        { 0,     +N, +1 },
        { N-1,   -1, +N },
        { N-1,   +N, -1 },
        { N*N-1, -1, -N },
        { N*N-1, -N, -1 },
        { N*N-N, +1, -N },
        { N*N-N, -N, +1 },
    };

    int order[N];

    for (u64 i = 0; i < 7; ++i) {
        u64 start = symmetries[i][0];
        u64 dcol = symmetries[i][1];
        u64 drow = symmetries[i][2];
        memset(order, 0xFF, N*sizeof(int));

        for (u64 row = 0, col = 0; col < N || (col = 0, ++row < N); ++col) {
            u64 base = board[col + N*row];
            u64 symmetry = board[start + dcol*col + drow*row];
            u64 lex = 0;

            while (order[lex] != symmetry && order[lex] != -1)
                ++lex;
            order[lex] = symmetry;

            if (lex < base)
                return 0;

            if (base < lex)
                break;
        }
    }

    return 1;
} 

static void recurse(u64 mino, u64 cell, u64 occupied, u64 adjacent, u64 forbidden)
{
    if (cell >= N) {
        ++mino;

        if (mino == N) {
            count += check_symmetry();
            return;
        }

        u64 next = ctz(~occupied);
        board[next] = mino;
        recurse(mino, 1, occupied | 1ul << next, adjacency_matrix[next], 0);
        return;
    }

    adjacent &= ~occupied & ~forbidden;
    while (adjacent) {
        u64 next = ctz(adjacent);
        adjacent &= ~(1ul << next);
        forbidden |= 1ul << next;
        board[next] = mino;
        recurse(mino, cell + 1, occupied | 1ul << next, adjacent | adjacency_matrix[next], forbidden);
    }
}

int main(void)
{
    for (u64 i = 0; i < N*N; ++i) {
        if (i % N)
            adjacency_matrix[i] |= 1ul << (i - 1);
        if (i / N)
            adjacency_matrix[i] |= 1ul << (i - N);
        if (i % N != N - 1)
            adjacency_matrix[i] |= 1ul << (i + 1);
        if (i / N != N - 1)
            adjacency_matrix[i] |= 1ul << (i + N);
    }

    recurse(0, 2, 3, 4 | 3 << N, 0);
    printf("%ld\n", count);
}

ลองออนไลน์! (สำหรับ N = 6 เนื่องจาก N = 7 จะหมดเวลา)

บนเครื่องของฉัน N = 6 ใช้เวลา 0.171 วินาทีและ N = 7 ใช้เวลา 2m23s N = 8 อาจใช้เวลาสองสามสัปดาห์


3
มันวิเศษมาก! แจ้งให้เราทราบหากคุณต้องการเพิ่มลงใน OEIS ซึ่งอาจส่งผลให้คุณเพิ่มตัวคุณเอง - หรือถ้าคุณต้องการให้ฉันเพิ่มเข้าไป
Peter Kagey

@PeterKagey โปรดเพิ่มเข้าไป (:
Grimmy

ฟังก์ชั่น check_symmetry ที่น่าสนใจ คุณช่วยอธิบายสั้น ๆ ได้ไหมเพราะฉันไม่คุ้นเคยกับวิธีการนี้?
John Rees

1
@ JohnRees มันแค่ทดสอบว่าบอร์ดปัจจุบันมีการใช้พจนานุกรม x กับความสมมาตรทั้งหมดของมัน ดังนั้นในชุดของกระดานสมมาตรใด ๆ นับเป็นหนึ่ง: ขั้นต่ำการทำพจนานุกรม
Grimmy

ในการทำดีกว่าการแจกแจงโซลูชันทีละรายการจำเป็นต้องพบปะกันในรูปแบบกลาง ปัญหาคือดูเหมือนจะไม่มีทางที่จะแยกสิ่งต่าง ๆ ออกซึ่งทำให้เกิดการรวมกลุ่มที่สำคัญ เช่นใช้การจัดลำดับแบบบัญญัติตามแบบเดียวกันกับคำตอบนี้การวาง 3 hexominoes ฉันได้รับเฉลี่ย 3.7 ชุด hexominos ต่อหน้ากาก ฉันสรุปได้ว่าวิธีนี้ไม่น่าจะถูกโจมตี
Peter Taylor
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.