Thuật toán để tạo tất cả các tập hợp điểm m trong mạng khối nxnxn là duy nhất theo đối xứng


10

Tôi đang thực hiện một thuật toán sẽ khá phức tạp về mặt tính toán và muốn thử đảm bảo rằng tôi không làm những việc không cần thiết.

Có một mạng tinh thể nxnxn, ví dụ: nếu n = 2, nó bao gồm (0,0,0), (0,1,0), (1,0,0), (1,1,0), (0, 1,1), (0,0,1), (1,0,1), (1,1,1).

Từ mạng này tôi sẽ tạo đệ quy tất cả các tập hợp điểm m, đại loại như:

solve(set_of_points) {
     if set_of_points.size = m, finish

     do some useful computation here

     for each point in lattice not in set_of_points:
         solve(set_of_points + new_point);
}

Điều này sau đó có thể được gọi bắt đầu với một set_of_point trống.

Bản chất của vấn đề là tôi thực sự không cần mọi hoán vị của điểm m, chỉ là những điểm duy nhất dưới các đối xứng tự nhiên của khối lập phương.

Ví dụ: lấy khối lập phương 2x2x2 và giả sử chúng ta muốn tất cả các bộ 1 điểm. Theo thuật toán cơ bản ở trên, có 8 bộ 1 điểm khác nhau.

Tuy nhiên, bằng cách sử dụng các đối xứng của khối lập phương, chúng ta có thể giảm xuống 1 bộ duy nhất 1 điểm, vì tất cả 8 điểm ban đầu đều tương đương theo các đối xứng của khối (trong trường hợp này đều là 'góc').

Nếu khối lập phương là 2x2x2 và m = 2, có 28 bộ trong thuật toán cơ bản, nhưng điều này giảm xuống chỉ còn 3 theo đối xứng (ví dụ: {(0,0,0), (1,0,0)}, {(0 , 0,0), (1,1,0)}, {(0,0,0), (1,1,1)})

Rõ ràng việc thực hiện tính toán trên 3 bộ điểm tốt hơn nhiều so với 28, vì vậy câu hỏi của tôi là làm thế nào để tôi không tạo ra các điểm tương đương đối xứng với một tập hợp đã được tạo? Hoặc nếu điều này là không thể, ít nhất tôi có thể giảm số lượng bộ một chút.

(Lưu ý - nếu m = 1 thì điều này tương đối dễ dàng - chỉ cần chọn các điểm gần (0,0,0) hơn bất kỳ đỉnh nào khác, với một chút sai lệch ở các ranh giới. Đó là cho m> 1 rằng điều này sẽ đạt được là một vấn đề thực sự)


1
Bằng cách đối xứng tương đương, bạn bao gồm các hoạt động: Máy bay gương qua trung tâm? Điểm đảo qua trung tâm? Tất cả ba trục 4 trục xuyên qua tâm?
BmyGuest

Bất kỳ hình học nào cũng sẽ thực hiện được mẹo
rbennett485

Nếu bạn vẫn ở đó, liệu sự lặp lại có được phép trong tập hợp các điểm không? Ví dụ: với m = 3, {(0,0,0), (1,1,1), (0,0,0)} có được coi là một lựa chọn hợp lệ không?
bôi đen

@blackpen không, nó cần có 3 điểm duy nhất
rbennett485

Câu trả lời:


1

Khái niệm cơ bản:

(1) Chúng ta có thể xem điểm (0,0,0) đơn giản là 000. Mỗi điểm trong mạng bây giờ rơi vào một chuỗi đơn giản. Điểm đầu tiên là 000, sau đó là 001, sau đó là 010 011 100 101 110 và 111. Đây là thứ tự mà bạn sẽ thử thêm chúng vào tập hợp điểm.

(2) Tương tự, tập {(0,0,0), (0,0,1), (0,1,0)} có thể được xem đơn giản là 000001010 và tập {(0,0,0) , (0,1,0), (0,0,1)} có thể được xem đơn giản là 000010001. Hai bộ khác nhau không thể có cùng một chuỗi và bạn có thể dễ dàng xem 000001010 dưới dạng số hoặc chữ cái nhỏ hơn 000010001. Hãy gọi đây là giá trị đặt. Bây giờ mọi tập hợp điểm N có thể có một giá trị tập hợp và tất cả các tập hợp điểm N có thể hiện nằm trong một danh sách được sắp xếp đơn giản.

(3) Mỗi ​​nhóm điểm đẳng hình có chính xác một thành viên sẽ có giá trị đặt thấp nhất. Đó là những người duy nhất mà chúng tôi thực sự làm "tính toán hữu ích".

(4) Đây là phần sẽ cần công việc quan trọng. Trước khi bạn chạy giải quyết (set_of_point + new_point), bạn muốn xem liệu có bất kỳ đẳng cấu nào sẽ hạ giá trị set cho set_of_point + new_point không. Nếu bất kỳ đẳng cấu nào sẽ làm giảm giá trị cài đặt thì đây KHÔNG phải là thành viên có giá trị thấp nhất của tập đẳng cấu. Chúng tôi bỏ qua thực hiện bất kỳ công việc trên new_point này. Chúng tôi cũng đang bỏ qua tất cả các công việc đệ quy mà chúng tôi đã thực hiện bên trong giải quyết này (set_of_point, Ứng viên_point).

solve(set_of_points,new_point) {
 set_of_points = set_of_points + new_point
 do some useful computation here
 if set_of_points.size = m, compute how many isomophisms exist, apply that multiple, finish
 for(candidate_point = new_point+1 to last_point) { /skips point-permutations for free!/
  if ISOMORPH_TESTS_CANNOT_LOWER_VALUE_OF(set_of_points+candidate_point) {
   solve(set_of_points,candidate_point);
  }
 }
}

1

lấy ký hiệu của câu trả lời ở trên.

trước tiên hãy xác định ký hiệu được đề xuất bởi hàm xoay (hướng, số_of_time)

giải pháp:

(1) tạo hàm băm của tất cả các bộ hoán vị với cờ = 0 trên mỗi bộ. ví dụ: n = 2, m = 2 000,001 = 0 000,010 = 0 000,011 = 0 ect '...

(2) bắt đầu từ bộ init, ví dụ i = 000.001

(3) xoay tập i sang tất cả các hướng bằng cách sử dụng chức năng xoay (hoặc bất kỳ đối xứng nào khác mà bạn thích), ví dụ, chức năng xoay phải được gọi 24 lần cho mỗi lần hoán vị của phép quay.

nhập mô tả hình ảnh ở đây

giải thích: bất kỳ số 1-6 nào cũng có thể ở trước mặt bạn và mỗi số có thể xoay 4 lần, do đó 6 * 4 = 24

(4) cho mỗi bộ được lấy lại từ tổ hợp, đặt cờ băm thành 1 (nó đã có bộ đối xứng)

(5) cập nhật i cho tập tiếp theo, ví dụ i = 000,010

(6) nếu tập i trong hàm băm đã được đánh dấu, hãy chuyển đến (5) nếu không đi đến (3)

chúng ta đã hoàn thành khi tất cả hàm băm được đánh dấu là 1.


Tôi khá thích cách tiếp cận này, nhưng nó sẽ không hữu ích cho vấn đề ban đầu (không phải tôi đã nói với bạn nó là gì!). Lý do là điều này vẫn đòi hỏi phải tạo ra từng bộ điểm và công việc tôi phải làm với mỗi bộ là rất nhỏ nên điều này có thể sẽ tăng thêm chi phí khi nó được lưu. Đối với các ứng dụng có nhiều tính toán cần thực hiện cho mỗi bộ, điều này sẽ rất hữu ích
rbennett485

1

Lưu ý: Tôi chỉ nghĩ về đối xứng gương, không phải đối xứng quay ở đây.

Giả sử chúng ta có một khối (siêu) có kích thước d , mỗi chiều dài n đơn vị (khối Rubik sẽ là d = 3, n = 3 ).

Một thuật toán ngây thơ sẽ tạo ra n ^ d kết hợp các điểm và kiểm tra từng điểm cho một xung đột đối xứng với tất cả các điểm khác.

Nếu chúng ta biểu diễn một tổ hợp các điểm dưới dạng một vectơ bit dài n ^ d bit, chúng ta có thể sử dụng bản đồ (vectơ bit -> boolean) để đánh dấu tất cả các đối xứng của vectơ bit là đúng . Sau đó chúng ta có thể bỏ qua một sự kết hợp nếu nó đã được đánh dấu trên bản đồ.

Cách tiếp cận này rất không hiệu quả về không gian: nó cần một bản đồ với 2 ^ (n ^ d) , tức là một bitmap có nhiều bit này. (Đối với khối Rubik, nó sẽ là 2 ^ 27 = 128Mbit = 16 Mbyte.)

Chúng ta chỉ có thể nhớ các biểu diễn chính tắc, nghĩa là các vectơ bit như vậy có giá trị nguyên nhỏ nhất, nếu được biểu diễn dưới dạng một từ không dấu n ^ d -bit. Khi chúng tôi tạo ra một hoán vị điểm mới, chúng tôi tạo ra tất cả các đối xứng của nó và chỉ kiểm tra xem chúng tôi đã thấy đối xứng có giá trị số nhỏ nhất chưa. Điều này sẽ cho phép chúng tôi lưu trữ một bản đồ chỉ với 2 ^ n bit (chỉ 1 byte cho khối Rubik), bởi vì chúng tôi có 2 ^ d đối xứng. Tuy nhiên, điều này khiến chúng ta tạo ra 2 ^ d đối xứng trên mỗi bước, vì vậy chúng ta dành thời gian O (2 ^ (d ^ n + d)) = O (2 ^ (d ^ n) * 2 ^ d) . Vẫn nghèo.

Chúng ta có thể áp dụng ý tưởng từ đoạn trước cho trường hợp 1 chiều. Để tạo tất cả các kết hợp trong một vectơ có độ dài d , chúng ta chỉ cần tăng một số nhị phân d bit dài, bắt đầu từ tất cả 0s. Chúng ta hãy chia vectơ của chúng ta thành hai đoạn dài d / 2 , ví dụ: trái và phải. Chúng ta có thể nhận thấy rằng đối với mỗi 1bit trong phân đoạn bên trái, chúng ta chỉ cần xem các kết hợp có 1bit ở vị trí đối xứng của phần bên phải. Nếu không, chúng ta đã tạo ra một sự kết hợp đối xứng trước đó, khi vị trí của các bit được hoán đổi và 0xuất hiện trước dấu 1. Bằng cách này, cho mọi vị trí bit ở nửa bên phải (r) và vị trí đối xứng ở nửa bên trái(l) chúng ta chỉ cần tạo 3 kết hợp: (l = 0, r = 0); (l = 1, r = 1); (l = 1, r = 0) . Do đó, chúng ta chỉ cần tạo ra 2 ^ (d / 2) hoán vị của một vectơ có độ dài d , mang lại 3 kết hợp cho mỗi hoán vị.

Một khối có kích thước d có thể được xây dựng từ các vectơ n ^ (d-1) . Thủ thuật trên cho chúng ta các vectơ rẻ hơn so với cách tiếp cận ngây thơ. Để tạo ra một khối, chúng ta cần thời gian O (n ^ (d-1) * 2 ^ (d / 2)) .

Nếu chúng ta nhìn vào khối lập phương dọc theo chiều của các vectơ 1 chiều của chúng ta, chúng ta có thể thấy rằng chúng ta không phải kiểm tra tính đối xứng dọc theo chiều này: trong khi tạo các hình khối, chúng ta loại bỏ các đối xứng cho mỗi vectơ liên quan.

Bây giờ nếu chúng ta nhìn qua chiều này, chúng ta có thể sử dụng lại cùng một mẹo.

Khi chúng ta nhìn qua, chúng ta nhìn vào ví dụ các bit đầu tiên của vectơ tạo một mặt phẳng cụ thể. Các bit này đại diện cho một vectơ bit 1 chiều. Chúng ta có thể loại bỏ hầu hết các kết hợp các bit của nó khỏi các lý do đối xứng, như được mô tả ở trên. Vì vậy, nếu chúng ta chọn một vectơ 1-d cụ thể của một khối (ví dụ trên cùng ngoài cùng bên trái), chúng ta có thể loại bỏ nhiều vectơ của cùng một mặt phẳng (ví dụ: trên cùng) dựa trên giá trị của một bit cụ thể. Vì vậy, đối với một vectơ ở vị trí đối xứng gương trên mặt phẳng, chúng ta có thể tránh việc tạo tất cả các kết hợp có thể có tập bit đó (hoặc không đặt), làm giảm đáng kể số lượng vectơ mà chúng ta phải tạo cho một mặt phẳng cụ thể. Mỗi bit bị loại bỏ một nửa số lượng vectơ có thể tại vị trí phản chiếu gương. Điều này cho chúng ta một chuỗi các mặt phẳng không có đối tác đối xứng dọc theo mỗi chiều.

Thủ thuật này có thể được áp dụng để tiếp tục tạo ra các hoán vị của các mặt phẳng sau dọc theo chiều thứ ba, v.v.

Mặc dù không phải là một thuật toán hoàn chỉnh, tôi hy vọng điều này sẽ giúp.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.