C
บทนำ
ตามที่ให้ความเห็นโดย David Carraher วิธีที่ง่ายที่สุดในการวิเคราะห์การเรียงตัวหกเหลี่ยมดูเหมือนว่าจะใช้ประโยชน์จาก isomorphism กับแผนภาพสามมิติของหนุ่มสาวโดยทั่วไปเป็น x, y สี่เหลี่ยมที่เต็มไปด้วยแท่งความสูงจำนวนเต็ม เมื่อแกน z ถูกเคลื่อนเขา
ฉันเริ่มต้นด้วยอัลกอริทึมสำหรับการหาผลรวมที่ตอบสนองต่อการปรับเพื่อการนับสมมาตรมากกว่าอัลกอริทึมที่เผยแพร่ซึ่งอิงจากอคติกับหนึ่งในสามแกนคาร์ทีเซียน
ขั้นตอนวิธี
ฉันเริ่มต้นด้วยการเติมเซลล์ของระนาบ x, y, และ z ด้วย 1 ในขณะที่ส่วนที่เหลือของพื้นที่ประกอบด้วยศูนย์ เมื่อทำเสร็จแล้วฉันจะสร้างเลเยอร์ลวดลายทีละชั้นโดยแต่ละชั้นจะมีเซลล์ที่มีระยะห่างแมนฮัตตัน 3D ทั่วไปจากจุดกำเนิด เซลล์สามารถมี 1 หากสามเซลล์ด้านล่างนั้นยังมี 1 หากหนึ่งในนั้นมี 0 จากนั้นเซลล์จะต้องเป็น 0
ข้อดีของการสร้างลวดลายในลักษณะนี้คือแต่ละชั้นมีความสมมาตรเกี่ยวกับเส้น x = y = z ซึ่งหมายความว่าแต่ละชั้นสามารถตรวจสอบได้อย่างอิสระสำหรับสมมาตร
การตรวจสอบความสมมาตร
สมมาตรของของแข็งมีดังนี้: 3 การหมุนรอบเกี่ยวกับ x = y = z line -> 3 การหมุนรอบเกี่ยวกับจุดศูนย์กลางหกเหลี่ยม; และการสะท้อนกลับ 3 x เกี่ยวกับระนาบ 3 อันที่มีเส้น x = y = z และแกน x, y, z -> แต่ละเส้นสะท้อนเกี่ยวกับเส้นผ่านมุมหกเหลี่ยม
เพิ่มความสมมาตรได้สูงสุด 6 เท่า เพื่อให้สมมาตรเต็มรูปแบบของรูปหกเหลี่ยมต้องพิจารณาความสมมาตรอีกรูปแบบหนึ่ง ของแข็งแต่ละตัว (สร้างขึ้นจาก 1) มีของแข็งเสริม (สร้างขึ้นจาก 0's) โดยที่ N เป็นเลขคี่, ของแข็งประกอบจะต้องแตกต่างจากของแข็งเดิม (เพราะเป็นไปไม่ได้ที่พวกมันจะมีจำนวนลูกบาศก์เท่ากัน) กระนั้นเมื่อของแข็งประกอบสมบูรณ์หันกลับมาจะพบว่าการแทนแบบ 2 มิติของมันในรูปแบบของเพชรนั้นเหมือนกัน (ยกเว้นการดำเนินการสมมาตร 2 เท่า) กับของแข็งดั้งเดิม เมื่อ N ยังคงเป็นไปได้ที่ของแข็งจะผกผันได้
สามารถเห็นได้ในตัวอย่างสำหรับ N = 2 ในคำถาม หากมองจากด้านซ้ายหกเหลี่ยมแรกจะมีลักษณะเป็นก้อนแข็งที่มีก้อนเล็ก ๆ 8 ก้อนในขณะที่รูปหกเหลี่ยมสุดท้ายนั้นดูเหมือนเป็นเปลือกเปล่าที่มี 0 ก้อนเล็ก ๆ หากมองจากด้านขวาการย้อนกลับจะเป็นจริง รูปหกเหลี่ยมที่ 3, 4 และ 5 และรูปหกเหลี่ยมที่ 16, 17 และ 18 ดูเหมือนว่าพวกเขามีทั้ง 2 หรือ 6 ก้อนและประกอบกันใน 3 มิติ พวกมันเกี่ยวข้องกันใน 2 มิติโดยการดำเนินการสมมาตร 2 เท่า (การหมุน 2 เท่าหรือการสะท้อนเกี่ยวกับแกนผ่านขอบของรูปหกเหลี่ยม) ในทางกลับกันรูปหกเหลี่ยมที่ 9, 10, 11 และ 12 แสดงรูปแบบ 3 มิติซึ่ง เป็นส่วนเติมเต็มของตัวเองและดังนั้นจึงมีความสมมาตรที่สูงขึ้น (เหล่านี้จึงเป็นรูปแบบเดียวที่มีหลายหลากคี่)
โปรดทราบว่าการมี (N ^ 3) / 2 คิวบ์เป็นเงื่อนไขที่จำเป็นในการเติมเต็มด้วยตนเอง แต่โดยทั่วไปจะไม่เพียงพอหาก N> 2 ผลลัพธ์ของสิ่งนี้คือว่าสำหรับคี่ N, การเอียงเกิดขึ้นเสมอในคู่ (N ^ 3) / 2 ลูกบาศก์ต้องได้รับการตรวจสอบอย่างรอบคอบ
รหัสปัจจุบัน (สร้างผลรวมที่เหมาะสมสำหรับ N = 1,2,3,5 ข้อผิดพลาดตามที่กล่าวไว้สำหรับ 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]);
}
เอาท์พุต
โปรแกรมสร้างตารางผลลัพธ์ 8 รายการตาม 8 สมมาตรของของแข็ง ของแข็งสามารถมีสมมาตรใด ๆ ของ 4 ดังต่อไปนี้ (สัญกรณ์ Schoenflies)
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)
นอกจากนี้เมื่อของแข็งมีครึ่งหนึ่งของเซลล์ที่มี 1 และครึ่งหนึ่งเป็น 0 มีความเป็นไปได้ที่จะพลิก 1 และ 0 ทั้งหมดแล้วแปลงค่าพิกัดผ่านจุดศูนย์กลางของพื้นที่ลูกบาศก์ นี่คือสิ่งที่ฉันเรียกว่าเติมเต็มตัวเอง แต่ศัพท์ทางคณิตศาสตร์ที่มากกว่านั้นก็คือ
การดำเนินการแบบสมมาตรนี้ให้แกนหมุน 2 เท่าในการเรียงหกเหลี่ยม
รูปแบบที่มีความสมมาตรนี้จะแสดงรายการในคอลัมน์แยกต่างหาก พวกมันจะเกิดขึ้นเมื่อ N ยังเท่ากัน
การนับของฉันดูเหมือนจะปิดเล็กน้อยสำหรับ N = 4 ในการสนทนากับ Peter Taylor ดูเหมือนว่าฉันไม่ได้ตรวจจับการเอียงซึ่งมีความสมมาตรของเส้นผ่านขอบหกเหลี่ยมเท่านั้น นี่น่าจะเป็นเพราะฉันไม่ได้ทดสอบความสมบูรณ์ของตัวเอง (antisymmetry) สำหรับการดำเนินการอื่นที่นอกเหนือจาก (การผกผัน) x (อัตลักษณ์) การทดสอบเพื่อความสมบูรณ์ของตัวเองสำหรับ operatons (ผกผัน) x (การสะท้อนกลับ) และ (ผกผัน) x ) อาจเปิดเผยส่วนที่หายไป จากนั้นฉันคาดหวังว่าบรรทัดแรกของข้อมูลสำหรับ N = 4 จะมีลักษณะเช่นนี้ (ลดลง 16 ใน c1 และอีก 32 ใน C1):
c1 224064/12=18672 C1 534/6=89
วิธีนี้จะทำให้จำนวนรวมสอดคล้องกับคำตอบของปีเตอร์และhttps://oeis.org/A066931/a066931.txt
กระแสไฟขาออกมีดังนี้
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
รายการสิ่งที่ต้องทำ (อัพเดท)
จัดระเบียบโค้ดปัจจุบันให้เป็นระเบียบ
เสร็จแล้วไม่มากก็น้อย
ใช้การตรวจสอบความสมมาตรของเลเยอร์ปัจจุบันและส่งผ่านพารามิเตอร์สำหรับความสมมาตรของเลเยอร์ก่อนหน้า (ไม่มีจุดตรวจสอบว่าเลเยอร์สุดท้ายนั้นไม่สมมาตรหรือไม่)
เสร็จสิ้นผลลัพธ์สำหรับคี่ N เห็นด้วยกับข้อมูลที่เผยแพร่
เพิ่มตัวเลือกเพื่อระงับการนับตัวเลขอสมมาตร (ควรรันเร็วกว่ามาก)
ซึ่งสามารถทำได้โดยการเพิ่มเงื่อนไขอื่นในการเรียกซ้ำ: if(s1 && m<n*3-2)f(m + 1,e+d,s1)
ลดเวลาการทำงานสำหรับ N = 5 จาก 5 นาทีลงเหลือประมาณหนึ่งวินาที เป็นผลให้บรรทัดแรกของผลลัพธ์กลายเป็นขยะทั้งหมด (เช่นเดียวกับผลรวมโดยรวม) แต่ถ้ารวมแล้วเป็นที่รู้จักจาก OEIS จำนวนของการเอียงไม่สมมาตรสามารถสร้างขึ้นใหม่อย่างน้อยสำหรับคี่เอ็นที่แปลก
แต่สำหรับแม้แต่ N จำนวนของแข็งที่ไม่สมมาตร (ตามสมการ c3v) ที่เป็นส่วนประกอบที่สมบูรณ์จะหายไป สำหรับกรณีนี้โปรแกรมแยกต่างหากที่อุทิศให้กับของแข็งที่มี (N ** 3) / 2 เซลล์ที่มี 1 อาจมีประโยชน์ ด้วยสิ่งนี้ที่มีอยู่ (และนับอย่างถูกต้อง) อาจเป็นไปได้ที่จะลอง N = 6 แต่จะใช้เวลานานในการรัน
ใช้การนับเซลล์เพื่อลดการค้นหาสูงสุด (N ^ 3) / 2 ก้อน
ยังไม่เสร็จคาดว่าจะประหยัดได้
ใช้การตรวจสอบความสมมาตร (ของแข็งเสริม) สำหรับรูปแบบที่มี (N ^ 3) / 2 ลูกบาศก์อย่างแน่นอน
เสร็จสิ้น แต่ดูเหมือนจะมีการละเว้นให้ดู N = 4
ค้นหาวิธีเลือกตัวเลขที่ต่ำที่สุดจากคำที่ไม่สมมาตร
การออมไม่คาดว่าจะเป็นสิ่งที่ยอดเยี่ยม ตัวเลขที่ไม่สมส่วนจะช่วยกำจัดสิ่งนี้ได้ส่วนใหญ่ ภาพสะท้อนเดียวที่ถูกตรวจสอบคือระนาบผ่านแกน y (x และ z ถูกคำนวณในภายหลังโดยการคูณด้วย 3) ตัวเลขที่มีสมมาตรแบบหมุนเท่านั้นจะถูกนับในรูปแบบ enantiomeric บางทีมันอาจจะวิ่งเร็วเป็นสองเท่าหากนับเพียงครั้งเดียว
เพื่ออำนวยความสะดวกในเรื่องนี้อาจปรับปรุงวิธีการระบุพิกัดในแต่ละเลเยอร์ (จะสร้างกลุ่มที่เลวลงของ 6 หรือ 3 โดยอาจเป็นกลุ่มที่ 1 ในศูนย์กลางที่แน่นอนของเลเยอร์)
ที่น่าสนใจ แต่อาจมีคำถามอื่น ๆ ในเว็บไซต์เพื่อสำรวจ
N = 6
ให้ผลลัพธ์มากกว่า 10 ^ 12 โซลูชันที่ไม่สร้างสรรค์จึงจำเป็นต้องได้รับผลกระทบ