Lenguaje C: problema de la Torre de Hanoi (pasos en movimiento, número de pasos, movimiento real)

1. Descripción del problema

  Hay 3 pilares A, B y C, y el pilar A se coloca de abajo hacia arriba con nn de grande a pequeñon placas. Ahora se requiere usar B para mover todas las placas de A a C. Las condiciones de movimiento son:
(1) solo se puede mover una placa a la vez,
(2) la placa pequeña no puede aparecer debajo de la placa grande durante el movimiento proceso.

  Con n = 3 n=3norte=3 como ejemplo, debido a que la cantidad de placas es pequeña, es fácil obtener el siguiente método de movimiento.
1 2 3 ABC \begin{matriz} 1& & \\ 2& & \\ 3& & \\ \mathrm{A}&\mathrm{B}&\mathrm{C} \end{matriz}123unBc → \a 2 3 1 ABC \begin{matriz} & & \\ 2& & \\ 3& &1 \\ \mathrm{A}&\mathrm{B}&\mathrm{C} \end{matriz}23unB1c → \a 3 2 1 ABC \begin{matriz} & & \\ & & \\ 3& 2&1 \\ \mathrm{A}&\mathrm{B}&\mathrm{C} \end{matriz}3un2B1c → \a 1 3 2 ABC \begin{matriz} & & \\ & 1& \\ 3& 2& \\ \mathrm{A}&\mathrm{B}&\mathrm{C} \end{matriz}3un12Bc → \a 1 2 3 ABC \begin{matriz} & & \\ & 1& \\ & 2&3 \\\mathrm{A}&\mathrm{B}&\mathrm{C} \end{matriz}un12B3c → \a 1 2 3 ABC \begin{matriz} & & \\ & & \\ 1& 2&3 \\ \mathrm{A}&\mathrm{B}&\mathrm{C} \end{matriz}1un2B3c → \a 2 1 3 ABC \begin{matriz} & & \\ & &2 \\ 1& &3 \\ \mathrm{A}&\mathrm{B}&\mathrm{C} \end{matriz}1unB23c → \a 1 2 3 ABC \begin{matriz} & &1 \\ & &2 \\ & &3 \\ \mathrm{A}&\mathrm{B}&\mathrm{C} \end{matriz}unB123c

2. Ideas para resolver problemas

  ver n = 3 n=3norte=La idea básica de mover 3
es: (1) mover 1 y 2 de A a B;
(2) mover los 3 restantes más grandes de A a C;
(3) mover 1 y 2 de B a B; 2 mover a C;
  extender a nnn placas:1 ∼ n − 1
en A1norte1 se mueve a B;
(2) Deja A con el mayornnMueva n a C,1 ∼ n − 1
en B1norte1 se mueve a C;
  se puede encontrar que el paso (1, 3) es solo un n − 1 n-1norte1 es el problema de la Torre de Hanoi, pero mover A a C se convierte en A moviéndose a B y B moviéndose a C. Esto lleva a la idea de solución recursiva.

3. Implementación de código de paso móvil

#include <stdio.h>

void Hanoi(int n, char A, char B, char C){
    
    
	if (n == 1)
		printf("%c --> %c\n", A, C);
	else{
    
    
		Hanoi(n - 1, A, C, B);
		printf("%c --> %c\n", A, C);
		Hanoi(n - 1, B, A, C);
	}
}

main() {
    
    
	Hanoi(3, 'A', 'B', 'C');
	return 0;
}

Resultado de salida:

A --> C
A --> B
C --> B
A --> C
B --> A
B --> C
A --> C

4. Cálculo del número de pasos en movimiento.

  De acuerdo con las reglas de movimiento anteriores, se puede ver que para completar un nnLa Torre de Hanoi para n contendrá dosn − 1 n-1norte1 Torre de Hanoi más 1 movimiento,S n = 2 ∗ S n − 1 + 1 S_n = 2*S_{n-1}+1Sn=2Sn 1+1
   S 1 = 1 S_1 = 1S1=1
   S 2 = 2 ∗ S 1 + 1 = 2 ∗ 1 + 1 = 3 S_2 = 2*S_1+1 = 2*1+1=3S2=2S1+1=21+1=3
   S 3 = 2 ∗ S 2 + 1 = 2 ∗ ( 2 ∗ 1 + 1 ) + 1 = 7 S_3 = 2*S_2+1=2*(2*1+1)+1=7S3=2S2+1=2( 21+1 )+1=7
  Se puede encontrar que la ley esS n = 2 n − 1 + 2 n − 2 + ⋯ + 2 0 S_n = 2^{n-1}+2^{n-2}+\cdots+2^0Sn=2norte - 1+2norte - 2++20 , puede sumarse de acuerdo con la secuencia geométrica o considerarse comonnEl valor decimal correspondiente a un número binario con n bits todos 1, es decir,S n = 2 n − 1 S_n = 2^n-1Sn=2norte1 _

5. Hazlo realmente móvil

  El código anterior solo da los pasos de cómo moverse, pero en realidad no se da cuenta del movimiento en las tres torres. Se pueden dar los pasos habituales de la tarea de la Torre de Hanoi. Aquí añadimos un poco de dificultad para construir tres torres e imprimir el estado después de cada movimiento para lograr un movimiento real.
  De acuerdo con la forma de movimiento, solo la placa superior de una determinada torre se colocará en la parte superior de otra torre. La idea es tratar cada torre como una lista enlazada, cada placa es un nodo y la parte inferior de la torre es la cabeza de la lista enlazada. La parte superior de es la cola de la lista enlazada. Al moverse, el nodo de la cola de una torre se moverá a la cola de otra torre. Por lo tanto, es mejor registrar la dirección del nodo de la cola. La dirección de la cabeza se usa para imprimir las placas en la torre de abajo hacia arriba.
  El código de construcción de la lista enlazada es el siguiente:

typedef int TDataType;

typedef struct TowerNode {
    
    
	TDataType data;
	struct TowerNode* next;
	struct TowerNode* prev;
}TowerNode;

typedef struct Tower {
    
    
	TowerNode* head;
	TowerNode* tail;
}Tower;

void TowerInit(Tower* pt) {
    
    
	assert(pt);
	pt->head = NULL;
	pt->tail = NULL;
}

void TowerPush(Tower* pt, TDataType data) {
    
    
	assert(pt);
	TowerNode* newnode = (TowerNode*)malloc(sizeof(TowerNode));
	newnode->data = data;
	newnode->next = NULL;

	if (pt->head == NULL) {
    
    
		newnode->prev = NULL;
		pt->head = pt->tail = newnode;
	}
	else {
    
    
		newnode->prev = pt->tail;
		pt->tail->next = newnode;
		pt->tail = newnode;
	}
}

void TowerDestroy(Tower* pt) {
    
    
	assert(pt);
	TowerNode* cur = pt->head;
	while (cur) {
    
    
		TowerNode* next = cur->next;
		free(cur);
		cur = next;
	}
	pt->head = pt->tail = NULL;
}

void TowerMove(Tower* ptsrc, Tower* pttgt) {
    
    
	assert(ptsrc);
	assert(pttgt);
	TowerNode* srcnode = ptsrc->tail;
	if (srcnode->prev) {
    
    
		srcnode->prev->next = NULL;
		ptsrc->tail = srcnode->prev;
	}
	else {
    
    
		ptsrc->head = ptsrc->tail = NULL;
	}
	if (pttgt->head) {
    
    
		pttgt->tail->next = srcnode;
		srcnode->prev = pttgt->tail;
		pttgt->tail = srcnode;
	}
	else {
    
    
		pttgt->head = pttgt->tail = srcnode;
		srcnode->prev = NULL;
	}
}

void PrintTower(Tower t) {
    
    
	TowerNode* cur = t.head;
	while (cur) {
    
    
		printf("%d ", cur->data);
		cur = cur->next;
	}
	printf("\n");
}

  Los códigos de movimiento e impresión son los siguientes:
  la lógica del código es la misma, solo para garantizar que las torres de impresión estén en el orden ABC cada vez, y las tres listas vinculadas se colocan en una matriz.

void PrintTowerList(Tower* towerlist[3]) {
    
    
	printf("A: ");
	PrintTower(*towerlist[0]);
	printf("B: ");
	PrintTower(*towerlist[1]);
	printf("C: ");
	PrintTower(*towerlist[2]);
}

void Hanoi(int n, Tower* towerlist[3], int a, int b, int c) {
    
    
	static int count = 1;
	char str[] = {
    
     'A', 'B', 'C' };
	if (n == 1) {
    
    
		TowerMove(towerlist[a], towerlist[c]);
		printf("第%d步: %c --> %c\n", count, str[a], str[c]);
		count++;
		PrintTowerList(towerlist);
	}
	else {
    
    
		Hanoi(n - 1, towerlist, a, c, b);
		TowerMove(towerlist[a], towerlist[c]);
		printf("第%d步: %c --> %c\n", count, str[a], str[c]);
		count++;
		PrintTowerList(towerlist);
		Hanoi(n - 1, towerlist, b, a, c);
	}
}

int main()
{
    
    
	int n = 3;
	Tower towerA, towerB, towerC;
	TowerInit(&towerA);
	TowerInit(&towerB);
	TowerInit(&towerC);
	for (int i = n; i > 0; i--) {
    
    
		TowerPush(&towerA, i);
	}
	Tower* towerlist[3] = {
    
     &towerA, &towerB, &towerC };
	printf("初始状态\n");
	PrintTowerList(towerlist);

	Hanoi(n, towerlist, 0, 1, 2);
	TowerDestroy(&towerA);
	TowerDestroy(&towerB);
	TowerDestroy(&towerC);

	return 0;
}

  Resultado de salida:

初始状态
A: 3 2 1
B:
C:1: A --> C
A: 3 2
B:
C: 12: A --> B
A: 3
B: 2
C: 13: C --> B
A: 3
B: 2 1
C:4: A --> C
A:
B: 2 1
C: 35: B --> A
A: 1
B: 2
C: 36: B --> C
A: 1
B:
C: 3 27: A --> C
A:
B:
C: 3 2 1

Supongo que te gusta

Origin blog.csdn.net/weixin_43605641/article/details/124799050
Recomendado
Clasificación