직접적인 방법 중 하나는 각 호출에서 다음을 수행하는 재귀 프로 시저입니다. 프로 시저에 대한 입력은 이미 선택된 쌍의 목록과 모든 쌍의 목록입니다.
- 입력 목록에서 아직 다루지 않은 가장 작은 숫자를 계산하십시오. 첫 번째 호출의 경우 페어가 선택되지 않았으므로 0이됩니다.
- 모든 숫자가 적용되는 경우 올바른 조합을 갖고 인쇄 한 후 이전 단계로 돌아갑니다. 그렇지 않으면 발견되지 않은 가장 작은 숫자가 목표입니다.
- 대상 번호를 포함하는 방법을 찾기 위해 쌍을 검색하십시오. 없는 경우 이전 수준의 재귀로 돌아갑니다.
- 대상 번호를 처리 할 수있는 방법이있는 경우 첫 번째 방법을 선택하고 방금 선택한 쌍을 선택한 쌍 목록에 추가하여 전체 프로 시저를 재귀 적으로 다시 호출하십시오.
- 다시 돌아 오면 이전에 선택한 쌍과 겹치지 않고 대상 번호를 한 쌍으로 덮는 다음 방법을 찾으십시오 . 하나를 찾으면 선택하고 다음 절차를 재귀 적으로 호출하십시오.
- 대상 번호를 더 이상 덮을 방법이 없을 때까지 4 단계와 5 단계를 계속하십시오. 전체 쌍 목록을 살펴보십시오. 더 이상 올바른 선택이 없으면 이전 수준의 재귀로 돌아갑니다.
이 알고리즘을 시각화하는 방법은 경로가 겹치지 않는 쌍의 트리 인 트리를 사용하는 것입니다. 트리의 첫 번째 레벨에는 0을 포함하는 모든 쌍이 포함됩니다. 위의 예에서 트리는
뿌리
|
----------------
| | |
(0,1) (0,2) (0,3)
| | |
(2,3) (1,3) (1,2)
이 예에서 트리를 통과하는 모든 경로는 실제로 올바른 모음을 제공하지만, 예를 들어 (1,2) 쌍을 제외하면 가장 오른쪽 경로에는 하나의 노드 만 있고 3 단계의 검색에 해당합니다.
이 유형의 검색 알고리즘은 특정 유형의 모든 객체를 열거하는 많은 유사한 문제에 대해 개발 될 수 있습니다.
아마도 OP 는 질문이 말한 것처럼 단지 쌍이 아니라 모든 쌍이 입력에 있음을 의미한다고 제안했습니다 . 이 경우 더 이상 허용되는 쌍을 확인할 필요가 없으므로 알고리즘이 훨씬 더 쉽습니다. 모든 쌍의 세트를 생성 할 필요조차 없습니다. 다음 의사 코드는 OP가 요청한 것을 수행합니다. 여기서 은 입력 번호이고, "list"는 빈 목록으로 시작하고 "covered"는 0으로 초기화 된 길이 의 배열입니다. 좀 더 효율적으로 만들 수는 있지만 바로 나의 목표는 아닙니다.nnn
sub cover {
i = 0;
while ( (i < n) && (covered[i] == 1 )) {
i++;
}
if ( i == n ) { print list; return;}
covered[i] = 1;
for ( j = 0; j < n; j++ ) {
if ( covered[j] == 0 ) {
covered[j] = 1;
push list, [i,j];
cover();
pop list;
covered[j] = 0;
}
}
covered[i] = 0;
}