대칭에서 고유 한 nxnxn 입방 격자의 모든 m 점 세트를 생성하는 알고리즘


10

상당히 계산적으로 복잡한 알고리즘을 구현 중이며 불필요한 작업을 수행하지 않도록 노력하고 싶습니다.

nxnxn 입방 격자가 있습니다. 예를 들어 n = 2 인 경우 (0,0,0), (0,1,0), (1,0,0), (1,1,0), (0, 1,1), (0,0,1), (1,0,1), (1,1,1).

이 격자에서 나는 다음과 같은 모든 m 포인트 세트를 재귀 적으로 생성 할 것입니다.

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

그런 다음 빈 set_of_points로 시작하여 호출 할 수 있습니다.

문제의 본질은 실제로 m 점의 모든 순열이 필요하지 않으며 큐브의 자연 대칭에서 고유 한 점만 필요 합니다 .

예를 들어 2x2x2 큐브를 가져 와서 모든 1 점 세트를 원한다고 가정합니다. 위의 기본 알고리즘에 따라 8 개의 서로 다른 1 점 세트가 있습니다.

그러나 큐브의 대칭을 사용하면 큐브의 대칭에서 원래 8 개가 모두 동일하므로 (이 경우에는 모두 '모퉁이'이므로) 1 개의 고유 한 1 점 세트로이를 줄일 수 있습니다.

큐브가 2x2x2이고 m = 2 인 경우 기본 알고리즘에는 28 개의 세트가 있지만 대칭 (예 : {(0,0,0), (1,0,0)}, {(0 , 0,0), (1,1,0)}, {(0,0,0), (1,1,1)})

분명히 3 세트의 포인트에서 계산을 수행하는 것이 28보다 훨씬 낫습니다. 따라서 제 질문은 이미 생성 된 세트와 대칭 적으로 동일한 포인트 세트를 생성하지 않는 방법입니다. 또는 이것이 가능하지 않은 경우 어떻게 최소한 세트 수를 조금 줄일 수 있습니까?

(참고-m = 1 인 경우 비교적 쉽습니다. 경계에서 약간 헷갈 리면서 다른 정점보다 (0,0,0)에 가까운 점을 선택하면됩니다. m> 1의 경우 진짜 문제가 되려면)


1
대칭 적으로 동등한 것으로 다음 작업을 포함합니다. 중심을 통과하는 미러 평면? 센터를 통한 포인트 반전? 중심을 통과하는 4 개의 회전축 3 개?
BmyGuest

모든 등거리 변환은 트릭을 수행합니다
rbennett485

여전히 주위에 있다면 m 세트의 점에서 반복이 허용됩니까? 예를 들어, m = 3의 경우 {(0,0,0), (1,1,1), (0,0,0)}이 하나의 유효한 선택으로 간주됩니까?
blackpen

@blackpen 아니오, 3 개의 고유 한 포인트가 필요합니다
rbennett485

답변:


1

기본 사상:

(1) 점 (0,0,0)을 간단히 000으로 볼 수 있습니다. 격자의 각 점은 이제 간단한 순서로 떨어집니다. 첫 번째 점은 000, 001, 010 011 100 101 110 및 111입니다.이 점을 포인트 세트에 추가하는 순서입니다.

(2) 마찬가지로, {(0,0,0), (0,0,1), (0,1,0)} 집합은 간단히 000001010으로 표시 될 수 있으며 {(0,0,0) , (0,1,0), (0,0,1)}은 단순히 000010001로 표시 될 수 있습니다. 서로 다른 두 세트는 동일한 시퀀스를 가질 수 없으며 000001010을 숫자 또는 알파벳순으로 000010001보다 작은 것으로 쉽게 볼 수 있습니다. 이것을 설정 값이라고합시다. 가능한 모든 N 포인트 세트에는 이제 설정 값이 있으며, 가능한 모든 N 포인트 세트는 이제 간단한 순서로 정렬됩니다.

(3) 모든 동형 그룹의 포인트 세트는 설정 값이 가장 낮은 정확히 하나의 멤버를 갖습니다. 그것들이 실제로 "유용한 계산"을하는 유일한 것입니다.

(4) 중요한 작업이 필요한 부분이 있습니다. solve (set_of_points + new_point)를 실행하기 전에 동형이 set_of_points + new_point에 대한 설정 값을 낮추는 지 확인하려고합니다. 동형이 설정 값을 낮추면 동형 집합의 가장 낮은 값이 아닙니다. 이 new_point에 대한 작업은 생략합니다. 또한이 solve (set_of_points, candidate_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

위 답변의 표기법을 복용하십시오.

먼저 함수 회전 (방향, number_of_time)에 의해 제안 된 기호를 정의 할 수 있습니다

해결책:

(1) 각각에 플래그 = 0 인 모든 순열 세트의 해시를 만듭니다. 예를 들어 n = 2, m = 2 000,001 = 0 000,010 = 0 000,011 = 0 ect '...

(2) 초기화 세트에서 시작 (예 : i = 000,001)

(3) 예를 들어 회전 기능 (또는 원하는 다른 대칭)을 사용하여 세트 i를 모든 방향으로 회전하십시오. 회전 기능은 각 회전 순열에 대해 24 번 호출해야합니다.

여기에 이미지 설명을 입력하십시오

설명 : 숫자 1-6은 앞에있을 수 있으며 각 숫자는 4 번 회전 할 수 있으므로 6 * 4 = 24입니다.

(4) 조합에서 다시 각 세트에 대해 해시 플래그를 1로 설정하십시오 (이미 대칭 세트가 있음)

(5) i를 다음 세트로 업데이트합니다 (예 : i = 000,010).

(6) 해시의 세트 i가 이미 표시된 경우 (5)로 이동하고 그렇지 않으면 (3)으로 이동하십시오

모든 해시가 1로 표시되면 완료됩니다.


나는이 접근법을 아주 좋아하지만 원래 문제에 유용하지는 않습니다 (무엇을 말했는지는 아닙니다!). 그 이유는 여전히 각 포인트 세트의 생성이 필요하고 각 세트와 관련된 작업이 매우 작기 때문에 저장 한 것보다 많은 오버 헤드가 추가 될 수 있습니다. 각 세트에 대해 많은 계산을 수행하는 응용 프로그램의 경우이 방법이 유용합니다.
rbennett485

1

참고 : 나는 회전 대칭이 아닌 거울 대칭에 대해서만 생각합니다.

n 단위 길이 의 d 차원 의 (하이퍼) 큐브가 있다고 가정합시다 (루빅스 큐브는 d = 3, n = 3 ).

순진한 알고리즘은 포인트의 n ^ d 조합을 생성 하고 각각 다른 모든 것과의 충돌이 있는지 확인합니다.

점들의 조합을 비트 벡터 n ^ d 비트 길이로 나타내는 경우, 맵 (비트 벡터-> 부울)을 사용하여 비트 벡터의 모든 대칭을 true로 표시 할 수 있습니다. 지도에 이미 표시된 조합은 건너 뛸 수 있습니다.

이 방법은 공간이 매우 비효율적입니다. 2 ^ (n ^ d) 항목이있는 맵, 즉이 비트 수가 많은 비트 맵이 필요합니다. (루빅스 큐브의 경우 2 ^ 27 = 128Mbit = 16MB입니다.)

정규 표현, 즉 n ^ d- 비트 부호없는 단어 로 표현 된 경우 가장 작은 정수 값을 갖는 비트 벡터 만 기억할 수 있습니다 . 점의 새로운 순열을 생성 할 때 모든 대칭을 생성하고 가장 작은 숫자 값으로 대칭이 보이는지 확인합니다. 이것은 우리가 2 ^ d 대칭을 가지기 때문에 2 ^ n 비트 (루빅스 큐브의 경우 1 바이트) 만으로 맵을 저장할 수있게합니다 . 각 단계에서 2 ^ d 대칭을 생성 하므로 O (2 ^ (d ^ n + d)) = O (2 ^ (d ^ n) * 2 ^ d) 시간을 소비합니다. 여전히 가난합니다.

이전 단락의 아이디어를 1 차원 사례에 적용 할 수 있습니다. 길이 d 의 벡터에서 모든 조합을 생성하려면 모든 s 부터 시작 하여 이진수 d 비트를 길게 증가시킬 수 있습니다 0. 벡터를 두 개의 d / 2- 길이 세그먼트 (예 : 왼쪽과 오른쪽)로 나누겠습니다 . 1왼쪽 세그먼트의 각 비트에 1대해 오른쪽 섹션의 대칭 위치에 비트가있는 조합 만 볼 수 있습니다 . 그렇지 않으면 비트의 위치가 바뀌었을 때와 0가 앞에 오기 전에 이미 대칭 조합을 이미 생성했을 것 1입니다. 이런 식으로, 오른쪽 절반 (r) 의 모든 비트 위치 와 왼쪽 절반의 대칭 위치(l) 3 가지 조합 만 생성하면됩니다 : (l = 0, r = 0); (l = 1, r = 1); (l = 1, r = 0) . 따라서 길이 d 의 벡터의 2 ^ (d / 2) 순열 만 생성하면되므로 각 순열에 대해 3 개의 조합이 생성됩니다.

d 차원 의 큐브는 n ^ (d-1) 벡터 로 구성 될 수 있습니다 . 위의 트릭은 순진한 접근 방식보다 벡터를 더 저렴하게 제공합니다. 큐브를 생성하려면 O (n ^ (d-1) * 2 ^ (d / 2)) 시간이 필요합니다.

1 차원 벡터의 차원을 따라 큐브를 보면이 차원을 따라 대칭을 확인할 필요가 없음을 알 수 있습니다. 큐브를 생성하는 동안 관련 벡터마다 대칭을 제거합니다.

우리가 보면 지금 에 걸쳐 이 차원, 우리는 같은 트릭을 다시 사용할 수 있습니다.

우리가 보았을 때, 우리는 예를 들어 특정 평면을 만드는 벡터의 첫 비트를 봅니다. 이 비트는 1 차원 비트 벡터를 나타냅니다. 위에서 설명한 것처럼 대칭 이유로 인해 비트의 대부분의 조합을 제거 할 수 있습니다. 따라서 큐브의 특정 1 차원 벡터 (예 : 가장 왼쪽)를 선택하면 특정 비트 값을 기준으로 동일한 평면 (예 : 상단)의 많은 벡터를 제거 할 수 있습니다. 따라서 평면에서 거울 대칭 위치에있는 벡터의 경우 모든 조합에 해당 비트 세트 (또는 설정되지 않음)가있을 수 있으므로 특정 평면에 대해 생성해야하는 벡터 수를 크게 줄일 수 있습니다. 각각의 제거 된 비트는 거울 반사 위치에서 가능한 벡터의 수를 반으로 줄입니다. 이것은 각 차원을 따라 대칭 대응 물이없는 일련의 평면을 제공합니다.

이 트릭은 3 차원 등을 따라 다음 평면의 순열 생성을 추가로 제한하기 위해 적용될 수 있습니다.

완전한 알고리즘은 아니지만 이것이 도움이되기를 바랍니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.