네 기둥 HanoiTower - --- 달콤 한 지 고민 하 는 지
6311 단어 【Algorithm】
그러나 오늘 우리 가 토론 하 는 중점 은 간단 한 한 노 타 알고리즘 이 아니 라 세 기둥 한 노 타의 연장 이다.먼저 전형 적 인 삼 주 한 노 타 를 살 펴 보 자.
1, 3 주 한 노 타 (Hanoi Three):
삼 주 한 노 타 에 대한 이해 와 알고리즘 실현 에 익숙 하 실 거 라 고 생각 합 니 다.
나 는 여기 서 삼 주 한 노 타의 알고리즘 사상 을 간단하게 한 번 살 펴 보 았 다.
A, B, C 세 개의 기둥 이 있 고 A 기둥 에 n 개의 접시 가 있 는데 지금 은 A 에 있 는 모든 접 시 를 C 로 옮 겨 야 하 니 운반 횟수 가 가장 적은 절 차 를 밟 아 주세요.
알고리즘 사상:
1. A 위의 n - 1 개의 접 시 를 C 로 캐 시 하고 모두 B 기둥 으로 옮 깁 니 다.
2. A 에 남 긴 n 번 째 접 시 를 C 로 옮 깁 니 다. 기둥 위.
3. B 에 있 는 n - 1 개의 접 시 를 A 를 캐 시 로 하고 모두 C 기둥 으로 옮 깁 니 다.
알고리즘 을 쉽게 얻 을 수 있 는 재 귀 방정식 은 T (n) = 2 * T (n - 1) + 1 이 고 걸음 수 는 T (n) = 2 ^ n - 1 이 라 고 계산 하기 어렵 지 않다.
구체 적 인 코드 는 다음 과 같다.
void Move( char x, char y )
{
printf("%c --> %c
", x, y); // ,x-->y
}
void Hanoi_Three( int n, char a, char b, char c )
{
if( n <= 0 )
return ;
step++; // +1
if( n == 1 )
{
Move( a, c ); // a c
return ;
}
else
{
Hanoi_Three( n-1, a, c, b); // a n-1 c , b
Move( a, c ); // A n , C
Hanoi_Three( n-1, b, a, c); // b n-1 , a , c
}
}
2. 사주 한 노 타 (Hanoi Four):
기둥 이 네 개 일 때 접 시 를 모두 다른 기둥 으로 옮 기 는 것 만으로 도 난이 도 를 크게 낮 추 었 고 알고리즘 의 복잡 도 도 를 크게 낮 추 었 다.그러나 이때 가장 좋 고 절차 가 가장 적은 실현 방법 을 찾 으 려 면 난이 도 는 수량 급 을 올 린 것 이 라 고 할 수 있다.
어떤 사람들 은 왜 내 가 삼 주 한 노 타의 사상 을 사용 하 는 것 이 최적화 되 지 않 았 는 지 의심 할 수도 있다.
서 두 르 지 말고 내 가 천천히 너 에 게 말 할 게.
먼저 이런 '합 리 적 으로 보인다' 는 해법 을 살 펴 보 자.
가설, A, B, C, D 는 각각 소스 위치, 캐 시, 캐 시, 목적 위치 이다.
세 기둥 이 있 을 때, 우 리 는 A 의 앞 n - 1 접 시 를 B 에 캐 시 한 다음, n 접 시 를 C 기둥 에 놓 기 때문이다.
현재 상황 이 매우 좋 습 니 다. 캐 시 할 수 있 는 기둥 이 두 개 있 기 때문에 이동 이 더욱 편리 해 보 입 니 다. 원래 B 에 캐 시 할 n - 1 개의 접시 가 있 었 는데 지금 은 n - 2 개의 접시 일 뿐 이 고 n - 1 개의 접 시 를 C 에 캐 시 할 수 있 습 니 다.
구체 적 인 절 차 는 다음 과 같다.
1. A 에서 C, D 를 빌려 n - 2 개의 접 시 를 B 위로 이동한다.
2. n - 1 번 접 시 를 C 위로 옮 깁 니 다.
3. n 번 째 접 시 를 D 위로 옮 깁 니 다.
4. n - 1 번 접 시 를 D 위로 이동 합 니 다.
5. B 에서 A, C 를 빌려 n - 2 개의 접 시 를 모두 D 위로 이동한다.
보기에 매우 완벽 하 다. 필 자 는 한때 이 사상 이 허점 이 없다 고 생각 했다. 심지어 나 는 k 개의 기둥 인 한 노 타의 통용 방법 을 찾 았 다 고 생각 했다.내 가 이 글 을 볼 때 까지: 다 주 한 노 타 최 우수 알고리즘 디자인 탐구.
접시 가 최대한 겹 치지 않도록 걸음 수 를 최소 화 하 겠 다 고 생각 했 지만 절대 장담 할 수 는 없 었 다.아마도 접시 가 비교적 적은 상황 에서 가능 할 것 이다. 그러나 접시 가 증가 할 때, 그 남 은 것 은 단지 한 접시 의 기둥 만 이용 할 수 있다 (가능 한 최 적 화 는 여기에 있다).이렇게 하면 매번 이동 걸음 수 를 늘 렸 지만 다른 측면 에서 재 귀 수량 을 줄 였 기 때문에 우 리 는 이 안에서 균형 점 을 찾 아야 한다.
다음은 1941 년 에 미국의 J. S. Frame 이 제시 한 사주 한 노 타의 알고리즘 사상 을 Frame 알고리즘 이 라 고도 부른다.
1. 4 주 한 노 타 알고리즘 으로 A 기둥 윗부분 의 n - r 개의 접 시 를 C 기둥 과 D 기둥 을 통 해 B 기둥 위로 옮 깁 니 다 [F (n - r) 걸음].
2. 3 주 한 노 타 고전 알고리즘 으로 A 기둥 에 남 은 r 개의 접 시 를 C 기둥 을 통 해 D 기둥 으로 옮 깁 니 다 [2 ^ r - 1 단계] (상기 3 기둥 의 상황 참조).
3. 4 주 한 노 타 알고리즘 으로 B 기둥 에 있 는 n - r 개의 접 시 를 A 기둥 과 C 기둥 을 통 해 D 기둥 위로 옮 깁 니 다 [F (n - r) 보].
4. 위의 규칙 에 따라 모든 r (1 ≤ r ≤ n) 상황 에서 걸음 수 f (n) 를 구하 고 최소 로 최종 적 으로 해석 할 가치 가 있다.
따라서 Frame 알고리즘 의 귀속 방정식 은 다음 과 같다.
F(n)=min(2*F(n-r)+2^r-1),(1≤r≤n)。
여러분 은 사실 이 알고리즘 사상 은 우리 가 이전에 합 리 적 이 라 고 생각 했 던 알고리즘 과 대체적으로 일치 합 니 다. 차 이 는 그 가 우리 의 n - 2 개의 접 시 를 B 에 캐 시 하고 n - r 개의 접 시 를 B 기둥 에 옮 기 는 것 입 니 다.
차이 가 핵심 이라도 이 알고리즘 의 핵심 은 n 개의 접 시 를 계산 하 는 상황 에서 r 가 왜 값 을 계산 할 때 알고리즘 을 가장 잘 만 들 수 있 습 니까?
핵심 을 찾 으 면 우리 의 현재 임 무 는 명확 해진 다. 바로 r 값 에 대한 계산 이다.
여기 서 비교적 어 리 석 은 방법 인 매 거 를 제시 했다.일정한 범위 내의 n 과 r 의 모든 값 을 가 져 와 F (n) 를 최소 값 으로 만족 시 키 는 r 의 값 을 얻 고 K [n] = r 로 기록 하 는 것 입 니 다.
구체 적 인 코드 는 다음 과 같다.
void Init_K(void )
{
int i, k;
__int64 temp;
__int64 m[Max+1] = {0};
for( i = 1; i <= Max; i++ )
{
m[i] = INT_MAX;
for( k = 1; k <= i; k++ )
{
temp = 2*m[i-k] + (__int64)pow(2,k) - 1;
if( temp < m[i] )
{
m[i] = temp;
K[i] = k;
//printf("K[%d] = %d, m[i] = %d
", i, k, temp );
}
}
}
}
각 n 쌍 의 r 를 얻 은 후에 알고리즘 은 매우 간단 해 지고 구체 적 으로 다음 과 같이 실현 된다.
#include
#include
#define Max 100
#define INT_MAX 0xfffffffffffffff
int K[Max+1] = {0};
int step = 0;
void Hanoi_Four( int n, char a, char b, char c, char d );
void Hanoi_Three( int n, char a, char b, char c );
void Move( char x, char y );
void Move( char x, char y )
{
printf("%c --> %c
", x, y); // ,x-->y
}
void Hanoi_Three( int n, char a, char b, char c )
{
if( n <= 0 )
return ;
step++; // +1
if( n == 1 )
{
Move( a, c ); // a c
return ;
}
else
{
Hanoi_Three( n-1, a, c, b); // a n-1 c , b
Move( a, c ); // A n , C
Hanoi_Three( n-1, b, a, c); // b n-1 , a , c
}
}
void Hanoi_Four( int n, char a, char b, char c, char d )
{
if( n <= 0 )
return ;
if( n == 1 )
{
step++;
Move( a, d );
return ;
}
else
{
int kn = K[n];
//printf("kn = %d
", K[n]);
Hanoi_Four( n-kn, a, c, d, b ); // 4 A n- kn C D B
Hanoi_Three( kn, a, c, d ); // 3 A kn C D 。
Hanoi_Four( n-kn, b, a, c, d ); // 4 B n-r A C D
}
}
void Init_K(void )
{
int i, k;
__int64 temp;
__int64 m[Max+1] = {0};
for( i = 1; i <= Max; i++ )
{
m[i] = INT_MAX;
for( k = 1; k <= i; k++ )
{
temp = 2*m[i-k] + (__int64)pow(2,k) - 1;
if( temp < m[i] )
{
m[i] = temp;
K[i] = k;
//printf("K[%d] = %d, m[i] = %d
", i, k, temp );
}
}
}
}
int main()
{
int n;
Init_K();
printf("Please enter the number of the Plates:
");
while( scanf("%d", &n) != EOF )
{
step = 0;
Hanoi_Four( n, 'A', 'B', 'C', 'D' );
//Hanoi_Three( n, 'A', 'B', 'C' );
printf("**************************
Total Step: %d
", step );
printf("Please enter the number of the Plates:
");
}
return 0;
}
여기까지 사주 한 노 타의 알고리즘 은 기본적으로 끝났다.
관심 있 는 학생 들 은 다 주 한 노 타의 실현 방법 을 계속 요약 할 수 있 습 니 다. 교류 지 도 를 환영 합 니 다!
합 리 적 으로 보 이 는 배후 가 사실은 일종 의 사고 정세 일 때 가 많다.
년 10 월 5 일 22: 54: 17
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
알고리즘 - 교묘 한 포커 (C 언어)/* , “ ”, 。 : :A,2,....J,Q,K 13 。 , , 。 , , A; , , 2; ...... , , K。 , :A,2,3,4,5,6,7,8,9,10,J,Q,K , 。 , , “ ” , 。 */ #in...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.