C
Giới thiệu
Theo nhận xét của David Carraher, cách đơn giản nhất để phân tích ốp hình lục giác dường như là tận dụng sự đồng hình của nó với Biểu đồ trẻ 3 chiều, về cơ bản là một hình vuông x, y chứa đầy các thanh có chiều cao nguyên có chiều cao z phải giữ nguyên hoặc tăng khi trục z được tiếp cận.
Tôi đã bắt đầu với một thuật toán để tìm ra các tổng có thể thích ứng với việc tính đối xứng hơn so với thuật toán được công bố, dựa trên sự thiên vị đối với một trong ba trục cartesian.
Thuật toán
Tôi bắt đầu bằng cách lấp đầy các ô của các mặt phẳng x, y và z bằng 1, trong khi phần còn lại của khu vực chứa các số 0. Khi đã xong, tôi xây dựng lớp mẫu theo từng lớp, với mỗi lớp chứa các ô có khoảng cách manhattan 3D chung từ gốc. Một ô chỉ có thể chứa 1 nếu ba ô bên dưới cũng chứa 1. nếu bất kỳ ô nào chứa 0, thì ô đó phải là 0.
Ưu điểm của việc xây dựng mô hình theo cách này là mỗi lớp đối xứng với đường x = y = z. Điều này có nghĩa là mỗi lớp có thể được kiểm tra độc lập về tính đối xứng.
Kiểm tra đối xứng
Các đối xứng của vật rắn như sau: Xoay 3 lần về đường x = y = z -> Xoay 3 lần về tâm hình lục giác; và 3 x phản xạ về 3 mặt phẳng chứa đường thẳng x = y = z và mỗi trục phản xạ x, y, z -> về các đường thẳng qua các góc lục giác.
Điều này chỉ thêm tối đa 6 lần đối xứng. Để có được sự đối xứng đầy đủ của hình lục giác, một loại đối xứng khác phải được xem xét. Mỗi vật rắn (được xây dựng từ 1) có một vật rắn bổ sung (được xây dựng từ 0). Trong đó N là số lẻ, chất rắn bổ sung phải khác với chất rắn ban đầu (vì chúng không thể có cùng số khối). Tuy nhiên, khi vật rắn bổ sung được quay tròn, người ta sẽ thấy rằng biểu diễn 2D của nó như là một viên kim cương giống hệt nhau (ngoại trừ thao tác đối xứng 2 lần) với vật rắn ban đầu. Trong đó N là chẵn, có thể cho vật rắn tự nghịch đảo.
Điều này có thể được nhìn thấy trong các ví dụ cho N = 2 trong câu hỏi. Nếu nhìn từ bên trái, hình lục giác đầu tiên trông giống như một khối lập phương rắn với 8 hình khối nhỏ, trong khi hình lục giác cuối cùng trông giống như một cái vỏ rỗng với 0 hình khối nhỏ. Nếu nhìn từ bên phải, điều ngược lại là đúng. Các hình lục giác thứ 3, 4 và 5 và các hình lục giác thứ 16, 17 và 18 trông giống như chúng chứa 2 hoặc 6 khối, và do đó chúng bổ sung cho nhau theo 3 chiều. Chúng có liên quan với nhau theo 2 chiều bằng thao tác đối xứng 2 lần (xoay 2 lần hoặc phản chiếu về một trục qua các cạnh của hình lục giác.) Mặt khác, các hình lục giác 9, 10, 11 và 12 hiển thị các mẫu 3D. là những bổ sung riêng của họ, và do đó có tính đối xứng cao hơn (do đó đây là những mẫu duy nhất có bội số lẻ).
Lưu ý rằng có (N ^ 3) / 2 hình khối là điều kiện cần để tự bổ sung, nhưng nói chung nó không phải là điều kiện đủ nếu N> 2. Kết quả của tất cả điều này là đối với N lẻ, độ nghiêng luôn xảy ra theo cặp (N ^ 3) / 2 khối phải được kiểm tra cẩn thận.
Mã hiện tại (tạo tổng số đúng cho N = 1,2,3,5. Lỗi như đã thảo luận cho N = 4.)
int n; //side length
char t[11][11][11]; //grid sized for N up to 10
int q[29][192], r[29]; //tables of coordinates for up to 10*3-2=28 layers
int c[9]; //counts arrangements found by symmetry class. c[8] contains total.
//recursive layer counting function. m= manhattan distance, e= number of cells in previous layers, s=symmetry class.
void f(int m,int e,int s){
int u[64], v[64], w[64]; //shortlists for x,y,z coordinates of cells in this layer
int j=0;
int x,y,z;
for (int i=r[m]*3; i; i-=3){
// get a set of coordinates for a cell in the current layer.
x=q[m][i-3]; y= q[m][i-2]; z= q[m][i-1];
// if the three cells in the previous layer are filled, add it to the shortlist u[],v[],w[]. j indicates the length of the shortlist.
if (t[x][y][z-1] && t[x][y-1][z] && t[x-1][y][z]) u[j]=x, v[j]=y, w[j++]=z ;
}
// there are 1<<j possible arrangements for this layer.
for (int i = 1 << j; i--;) {
int d = 0;
// for each value of i, set the 1's bits of t[] to the 1's bits of i. Count the number of 1's into d as we go.
for (int k = j; k--;) d+=(t[u[k]][v[k]][w[k]]=(i>>k)&1);
// we have no interest in i=0 as it is the empty layer and therefore the same as the previous recursion step.
// Still we loop through it to ensure t[] is properly cleared.
if(i>0){
int s1=s; //local copy of symmetry class. 1's bit for 3 fold rotation, 2's bit for reflection in y axis.
int sc=0; //symmetry of self-complement.
//if previous layers were symmetrical, test if the symmetry has been reduced by the current layer
if (s1) for (int k = j; k--;) s1 &= (t[u[k]][v[k]][w[k]]==t[w[k]][u[k]][v[k]]) | (t[u[k]][v[k]][w[k]]==t[w[k]][v[k]][u[k]])<<1;
//if exactly half the cells are filled, test for self complement
if ((e+d)*2==n*n*n){
sc=1;
for(int A=1; A<=(n>>1); A++)for(int B=1; B<=n; B++)for(int C=1; C<=n; C++) sc&=t[A][B][C]^t[n+1-A][n+1-B][n+1-C];
}
//increment counters for total and for symmetry class.
c[8]++; c[s1+(sc<<2)]++;
//uncomment for graphic display of each block stacking with metadata. not recommended for n>3.
//printf("m=%d j=%d i=%d c1=%d-2*%d=%d c3=%d cy=%d(cs=%d) c3v=%d ctot=%d\n",m,j,i,c[0],c[2],c[0]-2*c[2],c[1],c[2],c[2]*3,c[3],c[8]);
//printf("m=%d j=%d i=%d C1=%d-2*%d=%d C3=%d CY=%d(CS=%d) C3V=%d ctot=%d\n",m,j,i,c[4],c[6],c[4]-2*c[6],c[5],c[6],c[6]*3,c[7],c[8]);
//for (int A = 0; A<4; A++, puts(""))for (int B = 0; B<4; B++, printf(" "))for (int C = 0; C<4; C++) printf("%c",34+t[A][B][C]);
//recurse to next level.
if(m<n*3-2)f(m + 1,e+d,s1);
}
}
}
main()
{
scanf("%d",&n);
int x,y,z;
// Fill x,y and z planes of t[] with 1's
for (int a=0; a<9; a++) for (int b=0; b<9; b++) t[a][b][0]= t[0][a][b]= t[b][0][a]= 1;
// Build table of coordinates for each manhattan layer
for (int m=1; m < n*3-1; m++){
printf("m=%d : ",m);
int j=0;
for (x = 1; x <= n; x++) for (y = 1; y <= n; y++) {
z=m+2-x-y;
if (z>0 && z <= n) q[m][j++] = x, q[m][j++] = y, q[m][j++]=z, printf(" %d%d%d ",x,y,z);
r[m]=j/3;
}
printf(" : r=%d\n",r[m]);
}
// Set count to 1 representing the empty box (symmetry c3v)
c[8]=1; c[3]=1;
// Start searching at f=1, with 0 cells occupied and symmetry 3=c3v
f(1,0,3);
// c[2 and 6] only contain reflections in y axis, therefore must be multiplied by 3.
// Similarly the reflections in x and z axis must be subtracted from c[0] and c[4].
c[0]-=c[2]*2; c[2]*=3;
c[4]-=c[6]*2; c[6]*=3;
int cr[9];cr[8]=0;
printf("non self-complement self-complement\n");
printf("c1 %9d/12=%9d C1 %9d/6=%9d\n", c[0], cr[0]=c[0]/12, c[4], cr[4]=c[4]/6);
if(cr[0]*12!=c[0])puts("c1 division error");if(cr[4]*6!=c[4])puts("C1 division error");
printf("c3 %9d/4 =%9d C3 %9d/2=%9d\n", c[1], cr[1]=c[1]/4, c[5], cr[5]=c[5]/2);
if(cr[1]*4!=c[1])puts("c3 division error");if(cr[5]*2!=c[5])puts("C3 division error");
printf("cs %9d/6 =%9d CS %9d/3=%9d\n", c[2], cr[2]=c[2]/6, c[6], cr[6]=c[6]/3);
if(cr[2]*6!=c[2])puts("cs division error");if(cr[6]*3!=c[6])puts("CS division error");
printf("c3v %9d/2 =%9d C3V %9d/1=%9d\n", c[3], cr[3]=c[3]/2, c[7], cr[7]=c[7]);
if(cr[3]*2!=c[3])puts("c3v division error");
for(int i=8;i--;)cr[8]+=cr[i];
printf("total =%d unique =%d",c[8],cr[8]);
}
Đầu ra
Chương trình tạo ra một bảng đầu ra gồm 8 mục, phù hợp với 8 đối xứng của vật rắn. Vật rắn có thể có bất kỳ 4 đối xứng như sau (ký hiệu Schoenfly)
c1: no symmetry
c3: 3-fold axis of rotation (produces 3-fold axis of rotation in hexagon tiling)
cs: plane of reflection (produces line of reflection in hexagon tiling)
c3v both of the above (produces 3-fold axis of rotation and three lines of reflection through the hexagon corners)
Ngoài ra, khi vật rắn có chính xác một nửa các ô có 1 và một nửa bằng 0, sẽ tồn tại khả năng lật tất cả các số 1 và 0, sau đó đảo ngược tọa độ qua tâm của không gian khối. Đây là những gì tôi đang gọi là tự bổ sung, nhưng một thuật ngữ toán học hơn sẽ là "đối xứng đối với một trung tâm đảo ngược."
Thao tác đối xứng này cho trục xoay 2 lần trong lát hình lục giác.
Các mẫu có đối xứng này được liệt kê trong một cột riêng. Chúng chỉ xảy ra khi N chẵn.
Số lượng của tôi có vẻ hơi giảm cho N = 4. Trong cuộc thảo luận với Peter Taylor, có vẻ như tôi không phát hiện ra những con nghiêng chỉ có sự đối xứng của một đường thẳng qua các cạnh lục giác. Điều này có lẽ là do tôi chưa thử nghiệm tự bổ sung (đối xứng) cho các hoạt động khác ngoài (đảo ngược) x (nhận dạng.) Thử nghiệm để tự bổ sung cho các toán hạng (đảo ngược) x (phản xạ) và (đảo ngược) x (xoay 3 lần ) có thể phát hiện ra các đối xứng bị thiếu. Sau đó, tôi sẽ mong đợi dòng đầu tiên của dữ liệu cho N = 4 trông như thế này (16 ít hơn ở c1 và 32 nữa ở C1):
c1 224064/12=18672 C1 534/6=89
Điều này sẽ mang lại tổng số phù hợp với câu trả lời của Peter và https://oeis.org/A066931/a066931.txt
sản lượng hiện tại như sau.
N=1
non self-complement self-complement
c1 0/12= 0 C1 0/6= 0
c3 0/4 = 0 C3 0/2= 0
cs 0/6 = 0 CS 0/3= 0
c3v 2/2 = 1 C3V 0/1= 0
total =2 unique =1
non self-complement self-complement
N=2
c1 0/12= 0 C1 0/6= 0
c3 0/4 = 0 C3 0/2= 0
cs 12/6 = 2 CS 3/3= 1
c3v 4/2 = 2 C3V 1/1= 1
total =20 unique =6
N=3
non self-complement self-complement
c1 672/12=56 C1 0/6= 0
c3 4/4 = 1 C3 0/2= 0
cs 288/6 =48 CS 0/3= 0
c3v 16/2 = 8 C3V 0/1= 0
total =980 unique =113
N=4 (errors as discussed)
non self-complement self-complement
c1 224256/12=18688 C1 342/6=57
c3 64/4 =16 C3 2/2= 1
cs 8064/6 =1344 CS 54/3=18
c3v 64/2 =32 C3V 2/1= 2
total =232848 unique =20158
N=5
non self-complement self-complement
c1 266774112/12=22231176 C1 0/6= 0
c3 1100/4 =275 C3 0/2= 0
cs 451968/6 =75328 CS 0/3= 0
c3v 352/2 =176 C3V 0/1= 0
total =267227532 unique =22306955
Danh sách việc cần làm (cập nhật)
Dọn dẹp mã hiện tại.
Xong, nhiều hay ít
Thực hiện kiểm tra đối xứng cho lớp hiện tại và truyền tham số cho tính đối xứng của lớp trước đó (không có điểm nào trong việc kiểm tra xem lớp cuối cùng có bất đối xứng không.)
Xong, kết quả cho N lẻ đồng ý với dữ liệu được công bố
Thêm một tùy chọn để chặn số đếm không đối xứng (nên chạy nhanh hơn nhiều)
Điều này có thể được thực hiện bằng cách thêm một điều kiện khác vào lệnh gọi đệ quy: if(s1 && m<n*3-2)f(m + 1,e+d,s1)
Nó giảm thời gian chạy cho N = 5 từ 5 phút xuống còn khoảng một giây. Kết quả là dòng đầu tiên của đầu ra trở thành tổng rác (cũng như tổng số tổng thể) nhưng nếu tổng số đã được biết từ OEIS, số lượng nghiêng không đối xứng có thể được hoàn nguyên, ít nhất là cho số lẻ N.
Nhưng đối với N, số lượng chất rắn không đối xứng (theo đối xứng c3v) tự bù sẽ bị mất. Trong trường hợp này, một chương trình riêng dành riêng cho chất rắn có chính xác (N ** 3) / 2 ô có 1 có thể hữu ích. Với tính năng này có sẵn (và đếm chính xác), có thể thử N = 6, nhưng sẽ mất nhiều thời gian để chạy.
Thực hiện đếm các ô để giảm tìm kiếm lên tới (N ^ 3) / 2 khối.
Không được thực hiện, tiết kiệm dự kiến sẽ được cận biên
Thực hiện kiểm tra đối xứng (rắn bổ sung) cho các mẫu chứa chính xác (N ^ 3) / 2 khối.
Xong, nhưng dường như có thiếu sót, xem N = 4.
Tìm một cách để chọn con số thấp nhất từ vựng từ một con số không đối xứng.
Tiết kiệm không được mong đợi là tuyệt vời. Các số liệu bất đối xứng loại bỏ hầu hết điều này. Sự phản xạ duy nhất được kiểm tra là mặt phẳng qua trục y (x và z được tính sau bằng cách nhân với 3.) Các hình chỉ có đối xứng quay được tính ở cả hai dạng đối xứng của chúng. Có lẽ nó sẽ chạy nhanh gần gấp đôi nếu chỉ có một người được tính.
Để tạo điều kiện cho điều này, có thể cải thiện cách liệt kê các tọa độ trong mỗi lớp (chúng tạo thành các nhóm thoái hóa 6 hoặc 3, có thể là một nhóm 1 ở trung tâm chính xác của lớp.)
Thú vị nhưng có lẽ có những câu hỏi khác trên trang web để khám phá.
N = 6
cho đầu ra hơn 10 ^ 12, một giải pháp phi xây dựng gần như chắc chắn là cần thiết để đạt được điều đó.