Serbest n-polyominolu bir n X n karesinin belirgin eğim sayısı


17

En yeni "güzel" OEIS dizisi A328020 birkaç dakika önce yayınlandı.

Serbest n-polyomino ile bir n X n karesinin belirgin eğim sayısı.

Bu dizi, karenin simetrilerine kadar olan eğimleri sayar. Dizinin altı terimi vardır, ancak buradaki kişilerin daha da genişletip genişletemeyeceğini görmek istiyorum.

Misal

Çünkü n=4OEIS'ten bu resimde gösterildiği gibi 22 ızgara var. Kredi: Jeff Bowermaster, A328020 çizimi (4).A328020 (4)

Meydan okuma

Gibi bu önceki meydan , bu meydan okumanın amacı başlar bu dizinin, mümkün olduğunca çok sayıda terimler olarak hesaplamak için 1, 1, 2, 22, 515, 56734ve n-inci dönem n-Polyominoes n X n ızgaranın tilings sayısıdır.

Kodunuzu istediğiniz kadar çalıştırın. Bu zorluğun kazananı, diziyi en çok kullanan ve kodunu oluşturan kullanıcı olacak. İki kullanıcı aynı sayıda terim gönderirse, son terimini ilk kim paylaşırsa kazanır.


3
Peki bu karenin modulo simetrileri mi?
Peter Taylor

@PeterTaylor, doğru. Bunu soruda netleştirdim.
Peter Kagey

Safça n'th giriş hesaplamak için number_of_fixed_n_polyominoes ^ ( n -1) işlemleri alacağını söyleyebilirim . Bu nedenle n = 7 için 760 ^ 6 ≈ 2 ^ 57.4 işlem gerekir. Muhtemelen bunu çok fazla kesebilirsiniz, ancak başlamak için çok sayıda ...
G. Sliepen

@Sliepen, ben sadece geri takip ile bunu çok azaltabilirsiniz bekliyoruz. Özellikle, köşeye yerleştirilemez sabit polinomların bir yeri vardır ve geçerli bir polyomino kez olduğu bir yere yerleştirilen, o derece onun yanında yerleştirilebilir neler kısıtlar.
Peter Kagey

@PeterKagey, haklısın. Zaten m n-polominoları yerleştirmişseniz, bir polominoyu mümkün olan en kötü konuma yerleştirmeye çalışmak için bir sonraki konumu seçerseniz, çok fazla kesebileceğiniz faydalı olur.
G. Sliepen

Yanıtlar:


9

@ Grimy'nin koduna bir uzantı N = 8 alır

Bu @Grimy ödülünü hak ettiğini vurgulamaktadır:

Her bitmiş polyominodan sonra, kalan boş alanın N tarafından bölünemeyen boyuttaki bileşenlere bölünmediğini kontrol etmek için kodu uzatarak arama ağacını budayım.

Orijinal kodun N = 7 için 2m11s aldığı bir makinede, bu 1m4s alır ve N = 8, 33h46m'de hesaplandı. Sonuç 23437350133'tür.

İşte bir diff olarak benim ek:

--- 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);

Çevrimiçi deneyin!


Bu çok güzel.
Anush

Şimdi tek ihtiyacımız :) çok evreli bir SIMD sürümüdür
Anush

1
Oh, bu gerçekten harika! Aslında bu optimizasyonu düşündüm, ancak makul bir sürede N = 8'e ulaşmanın yeterli olacağını düşünmedim, bu yüzden uygulamayı zahmet etmedim.
Grimmy

14

C, 7 dönem

Yedinci dönem 19846102'dir . (İlk altı soruda belirtildiği gibi 1, 1, 2, 22, 515, 56734'tür).

#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);
}

Çevrimiçi deneyin! (N = 6 için, N = 7 zaman aşımına uğrayacağından.)

Makinemde N = 6 0.171 saniye ve N = 7 2m23 saniye aldı. N = 8 birkaç hafta alacaktı.


3
Bu harika! OEIS'e eklemek isteyip istemediğinizi (bu da kendinizi dolandırmanıza neden olabilir) veya eklememi isteyip istemediğinizi bize bildirin.
Peter Kagey

@PeterKagey Lütfen eklemek için çekinmeyin (:
Grimmy

Büyüleyici kontrol_simetri fonksiyonu. Yaklaşımı bilmediğim için lütfen kısa bir açıklama yapabilir misiniz?
John Rees

1
@JohnRees Mevcut anakartın sözlükbilimsel ≤ olduğunu ve tüm simetrilerini test eder. Böylece herhangi bir simetrik tahta setinde, tam olarak bir sayılır: sözlüksel minimum.
Grimmy

1
Çözümleri tek tek numaralandırmadan daha iyisini yapmak için, bir tür ortada buluşma gerekir. Sorun şu ki, önemli bir kümelenme olan şeyleri bölmenin bir yolu yok gibi görünüyor. Örneğin, bu cevapla aynı kanonik düzeni kullanarak, 3 hekzomino yerleştirerek, maske başına ortalama yaklaşık 3.7 set heksomino alırım. Bu yaklaşımın yenilmesi muhtemel olmadığı sonucuna varıyorum.
Peter Taylor
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.