말의 순회 문제. 8×8 개의 체크 무늬의 체스판에서, 임의의 지정된 체크 무늬부터 시작하여 말이 체스판의 각 체크 무늬를 한 번만 통과할 수 있는 경로를 찾습니다.
예비 설계
우선, 이것은 깊이 우선 검색으로 해결되는 검색 문제이다. 알고리즘은 다음과 같습니다.
1, 초기 위치 좌표 입력 x, y;
2. c 단계:
C & gt64 가 솔루션을 출력하고 이전 단계인 C-
(x, y) ← C.
계산 (x, y) 8 방향의 하위 노드에서 실행 가능한 하위 노드를 선택합니다.
실행 가능한 모든 하위 노드를 반복하고 2 에 대해 c++ 단계를 반복합니다.
분명히 (2) 는 다음과 같은 재귀 호출 프로세스입니다.
Void dfs(int x, int y, int count)
{
Int I, tx, ty;
If(count & gt;; N*N)
{
출력 솔루션 (); //솔루션 입력
반환;
}
For(I = 0;; 나<8; ++i)
{
Tx=hn[i] 입니다. X; //hn[] 8 개의 방위각 하위 노드를 저장합니다.
Ty=hn[i] 입니다. Y;
S [tx] [ty] = count;
Dfs(tx, ty, count+1); //재귀적 호출
S [tx] [ty] = 0;
}
}
이렇게 하는 것은 완전히 실행 가능한 것이다. 그것은 모든 해석을 입력했지만 말이 8×8 을 통과할 때, 해석이 너무 많아서 천문학적인 숫자로 묘사할 수 없기 때문에, 해결과정이 매우 느리고, 하나의 해결도 매우 느리다.
어떻게 하면 신속하게 일부 솔루션을 얻을 수 있습니까?
탐욕 알고리즘
사실 말이 바둑판을 밟는 문제는 일찌감치 제기됐고, 일찍이 1823, J.C.Warnsdorff 에서 유명한 알고리즘을 제시했다. 각 노드가 해당 하위 노드를 선택하면 출구가 가장 작은 노드가 먼저 선택됩니다. 종료' 는 이러한 하위 노드 중 실행 가능한 하위 노드의 수를 나타냅니다. 즉,' 손자' 노드가 적을수록 점프가 우선시됩니다. 왜 이런 방식을 선택했는가? 이것은 부분적인 최적화입니다. 먼저 출구가 많은 하위 노드를 선택하면 출구가 적은 하위 노드가 많아집니다. "죽음" 노드 (이름에서 알 수 있듯이 출구도 점프도 없는 노드) 가 나타날 가능성이 높기 때문에 뒤의 검색은 순전히 헛수고이며 쓸데없는 시간을 낭비할 수 있다. 반대로, 매번 우선 순위가 적은 노드를 탈퇴할 때마다 탈퇴하는 노드가 점점 줄어들면 성공할 확률이 더 높아진다. (윌리엄 셰익스피어, 햄릿, 성공명언) 이 알고리즘을 탐욕 알고리즘이라고 하며, 탐욕 알고리즘이나 계발적 알고리즘이라고도 합니다. 전체 솔루션 프로세스를 최적으로 조정하며 최적의 솔루션을 찾는 것이 아니라 더 나은 솔루션 또는 부분 솔루션을 찾는 데만 적합합니다. 이런 조정 방법을 탐욕 전략이라고 한다. 어떤 문제에 대해 어떤 욕심 전략이 필요한지, 불확실하고, 구체적인 문제를 구체적으로 분석하다. 실험에 따르면, 위에서 언급한 탐욕 전략을 적용한 후, 말 순회 문제의 해결 속도가 현저히 향상되었다. 단 하나의 해법만 요구하면 백트래킹 없이 완성할 수 있다. 이 알고리즘이 제기될 때 세상에 컴퓨터가 없기 때문에 이 방법은 완전히 수작업으로 해결할 수 있고, 효율은 상상할 수 있다.
이전 알고리즘을 기반으로 다음과 같은 프로그램을 추가합니다.
함수 1: 노드 출구 수를 계산합니다.
Int ways_out(int x, int y)
{
Int I, count=0, tx, ty;
If(x & lt;; 0 | | y<0 | | x> = n | | y> = n | | s [x] [y] > 0)
리턴-1; //- 1 노드가 잘못되었거나 건너뛰었음을 나타냅니다.
For(I = 0;; 나<8; ++i)
{
Tx = x+dx [I];
Ty = y+dy [I];
If(tx & lt;; 0 | | ty<0 | | tx>= N | | ty & gt=N)
계속;
If(s[tx][ty]==0)
++개수;
}
카운트 반환
}
기능 2: 노드 출구별 정렬
Void sortnode(h_node *hn, int n)// 하위 노드가 최대 8 개뿐이므로 간단한 정렬 방식을 사용합니다.
{
Int I, j, t;
H _ 노드 온도;
For(I = 0;; 나 & ltn;; ++i)
{
For(t=i, j = I+1; J & ltn;; ++j)
If(hn[j].waysout & lthn[t]. Waysout) 을 참조하십시오
T = j;;
If(t & gt;; 나)
{
Temp = HN [I];
Hn [I] = HN [t];
Hn [t] = temp;
}
}
}
기능 3: 수정된 검색 기능
Void dfs(int x, int y, int count)
{
Int I, tx, ty;
H _ node HN [8];
If(count & gt;; N*N)
{
출력 솔루션 ();
반환;
}
For(I = 0;; 나<8; ++i)// 하위 노드 찾기 및 종료
{
Hn[i]. X = tx = x+dx [I];
Hn[i]. Y = ty = y+dy [I];
Hn[i]. Waysout=ways_out(tx, ty);
}
Sortnode(hn, 8);
For(I = 0;; Hn[i]. Waysout & lt0; ++I); //불필요한 노드 고려 안 함
For (; 나<8; ++i)
{
Tx=hn[i] 입니다. X;
Ty=hn[i] 입니다. Y;
S [tx] [ty] = count;
Dfs(tx, ty, count+1);
S [tx] [ty] = 0;
}
}
기능 4: 음조 기능
Void main ()
{
Int I, j, x, y;
For(I = 0;; 나 & ltn;; ++i)// 초기화
For(j = 0;; J & ltn;; ++j)
S [I] [j] = 0;
Printf(" N =% d 시 틀 \ N 시작 위치 입력: ",n);
Scanf("%d%d ",& ampx & amp;; Y); //초기 위치 입력
While(x & lt;; 0 | | y<0 | | x>= N | | y & gt=N)
{
Printf ("오류! X, y 는 0~%d' 안에 있어야 합니다. n-1);
Scanf("%d%d ",& ampx & amp;; Y);
}
S [x] [y] =1;
Dfs(x, y, 2) : //검색 시작
}