Red de conocimientos turísticos - Conocimientos sobre calendario chino - Jiugongpin, encuentra una manera de resolver este problema~~Las ideas~el código está bien~~Se trata solo de su algoritmo de reducción, urgente~espera en línea. ~Gracias.

Jiugongpin, encuentra una manera de resolver este problema~~Las ideas~el código está bien~~Se trata solo de su algoritmo de reducción, urgente~espera en línea. ~Gracias.

/u/8780/showart.php? id=163291

En nueve palacios de 3 × 3, hay ocho números del 1 al 8 y un espacio colocados aleatoriamente en la cuadrícula, como se muestra en la Figura 1-1. Ahora debemos reconocer este problema: ajustarlo a la forma que se muestra en el lado derecho de la Figura 1-1. La regla de ajuste es que solo un número adyacente a un espacio (arriba, abajo, izquierda o derecha) se puede convertir en un espacio a la vez. Intente resolver este problema mediante programación.

(Figura 1-1)

2. Análisis de preguntas:

Este es uno de los problemas clásicos de la inteligencia artificial. El problema es que en un tablero de ajedrez de 3×3 se colocan 8 casillas y el resto están vacías. Cada jugada sólo se puede intercambiar con espacios adyacentes. El programa genera automáticamente el estado inicial del problema y lo transforma en el arreglo objetivo a través de una serie de acciones de intercambio (Figura 1-2 a Figura 1-3 a continuación).

(Figura 1-2)(Figura 1-3)

En este problema, la disposición aleatoria generada por el programa se convierte en el objetivo * * *. Hay dos posibilidades. , y ambos no pueden ser verdaderos al mismo tiempo, es decir, disposición impar y disposición par. Una matriz dispuesta aleatoriamente se puede representar mediante una matriz unidimensional de izquierda a derecha y de arriba a abajo. Como se muestra en la figura anterior, 1-2 se puede expresar como {8, 7, 1, 5, 2, 6, 3, 4, 0} donde 0 representa un espacio.

En esta matriz, primero calculamos el resultado que se puede reordenar, la fórmula es:

∑ (F(X)) = y, donde F(X)

es un número cuyo frente es menor que este número. Hay soluciones cuando y es un número impar y un número par. (8) Determine si existe una solución para el problema numérico)

La matriz anterior puede resolver su resultado.

f(8)= 0;

f(7)=

f(1)=

f; (5)= 1;

f(2)= 1;

f(6)= 3;

f(3)= 2;

p>

f(4)= 3;

y = 0 0 0 1 1 3 2 3 = 10

Y = 10 es un número par , por lo que su reordenamiento es Los resultados se muestran en la Figura 1-3. Si el resultado de la suma es un reordenamiento impar, el resultado es el arreglo más a la derecha, como se muestra en la Figura 1-1.

3. Análisis de algoritmos

La solución es intercambiar las posiciones de los espacios (0) hasta alcanzar la posición objetivo. La representación gráfica es:

(Figura 3-1)

Si desea obtener lo mejor, debe utilizar la búsqueda en amplitud, ¡por lo que hay 9 Jiugong! Hay 362.880 arreglos y la cantidad de datos es muy grande. Para utilizar la búsqueda amplia, es necesario recordar la disposición de cada nodo. Si usa una matriz para grabar, ocupará mucha memoria, por lo que los datos se pueden comprimir adecuadamente. Guardar en formato DWORD. La forma comprimida es que cada número está representado por 3 bits, que es 3×9 = 27 bytes. Debido a que la representación binaria de 8 es 1000, no se puede representar con 3 bits. Un truco consiste en representar 8 como 000 y luego usar las cinco palabras adicionales para representar la posición de 8, de modo que pueda representarse mediante DWORD. Usar operaciones de cambio y OR para mover datos uno por uno es más rápido que la multiplicación. Se definen varios resultados para almacenar los resultados del recorrido y la ruta óptima una vez completada la búsqueda.

La estructura de esta clase es la siguiente:

Cuadrícula de clasificación

{

Pública:

Lista de ubicaciones de estructuras

{

Deward Plaza;

PlaceList * Izquierda

PlaceList * Derecha

};

estructura Scanbuf

{

Deward Square;

int ScanID

};

Lista de rutas de estructura

{

Ruta de caracteres sin firmar[9];

};

Privado:

PlaceList * m _ pPlaceList

Scanbuf * m _ pScanbuf

RECT m _ rResetButton

RECT m _ Botón Lauto

Público:

int m _ iPathsize

reloj _ t m _ iTime

UINT m _ iStepCount

Charm sin firmar m _ iTargetChess[ 9];

Carácter sin firmar m _ I ajedrez[9];

HWND m _ hClientWin

PathList * m _ pPathList

bool m_botolun;

Privado:

embedded bool AddTree(lugar DWORD, PlaceList *amp parent);

void free tree(lugar lista * & parent);

Inline void ArrayToDword(matriz de caracteres sin firmar, datos de amplificador DWORD);

inline void DwordToArray(datos DWORD, matriz de caracteres sin firmar *);

inline bool MoveChess); (matriz de caracteres sin firmar, forma int);

bool EstimateUncoil(matriz de caracteres sin firmar);

void GetPath(profundidad de la unidad);

Público:

void move chess(int way);

bool ComputeFeel();

void active shaw(HWND h view);

void dibujar cuadrícula (HDC HDC, cliente RECT rect);

void DrawChess(HDC hDC, cliente RECT rect);

void Reset();

botón anular (haga clic en pnt, vista HWND h);

Público:

cningrid();

~cningrid();

};

Utilice una plantilla vectorial para calcular una matriz aleatoria, utilice la función random_shuffle() para codificar los datos de la matriz y calcule el resultado objetivo.

Código:

void cn inegrid::Reset()

{

if(m_bAutoRun) devuelve;

Vector vs; p>

int I;

for(I = 1;ilt9;i)

vs.push_back(一);

vs. push _ back(0);

random_shuffle(vs.begin(), vs.end());

random_shuffle(vs.begin(), vs.end())

for(I = 0;ilt9;i)

{

m _ iChess[I]= vs[I];

}

if (! estimación sin envolver (m_iChess))

{

Matriz de caracteres sin firmar[9] = {1, 2, 3, 8, 0, 4, 7, 6, 5};

memcpy(m_iTargetChess, array, 9);

}

Otros

{

Matriz de caracteres sin firmar[9] = {1, 2, 3, 4, 5, 6, 7, 8, 0};

memcpy(m_iTargetChess, matriz, 9) ;

}

m _ iStepCount = 0;

}

Implementación de la función de compresión de datos:

cninegrid vacío en línea::ArrayToDword(unsigned char *array, DWORD amp data)

{

Noche de caracteres sin firmar = 0;

for( int I = 0 ; i lt9; i )

{

if (matriz[i] == 8)

{

noche = (sin firmar) char)I;

Romper

}

}

matriz[noche]= 0;

p>

datos = 0;

datos =(DWORD)((DWORD)matriz[0] lt; lt29 |(DWORD)matriz[1] lt; lt26 |

(DWORD)matriz[2] lt23 |(DWORD)matriz[3] lt20 |

(DWORD)matriz[4] lt17 |(DWORD)matriz[5] lt; lt14 |

(DWORD)matriz[6] lt; lt11 |(DWORD)matriz[7] lt8 |

(DWORD)matriz[8] lt5 |noche );

array[night]= 8;

}

La descompresión y la compresión son exactamente lo contrario.

Código de descompresión:

Cninegrid vacío en línea::DwordToArray(datos DWORD, matriz de caracteres sin firmar)

{

Chatem de caracteres sin firmar

for(int I = 0; i lt9; i)

{

chtem = (carácter sin signo)(datos gt gt(32-(I 1)* 3);0x 000000007 );

matriz[I]= chtem;

}

chtem = (carácter sin firmar)(datos amp0x 0000001F);

array[chtem]= 8;

}

Debido a que la cantidad de datos escalables es muy grande, se utiliza el tipo DWORD al guardar y cada paso de datos se registra en un árbol En el árbol binario ordenado, ordenado de pequeño a grande de izquierda a derecha, el tiempo de búsqueda es casi n veces más rápido que casi 10.000 veces cada vez. Varias funciones utilizadas en el bucle se declaran como funciones en línea, mientras que los datos insertados se buscan duplicados en el árbol para acelerar la velocidad general. Código de inserción de árbol binario:

AddTree(DWORD place, PlaceList * amp parent)

{

if (parent == NULL)

{

padre = nueva lista de lugares();

padre->; izquierda = padre->; derecha = vacío;

padre- gt; = Lugar;

Devuelve verdadero

}

if(parent - gt; Lugar == lugar

Devuelve falso

if(parent-gt; Colocar ubicación gt)

{

Devuelve AddTree(lugar, parent-gt; par);

}

Devuelve AddTree(place, parent- gt; left);

}

Si el resultado del cálculo es un número par o impar:

bool CNI negrid ::estimate dependicle(unsigned char*array)

{

int sun = 0

for(int I = 0; i lt8; i)

{

for(int j = 0; j lt9; j)

{

si (matriz[ j]!= 0)

{

if (matriz[j] == i 1)

Romper;

if( matriz[j] lt;i 1)

sol;

}

}

}

si (sun 2 = = 0)

Devuelve verdadero

Otros

Devuelve falso

}

Código que se mueve al espacio Es relativamente simple. Solo necesita calcular si se moverá fuera del cuadro y, cuando se mueva, calcule si ya es el resultado objetivo, que se utiliza para darle al usuario movimientos e indicaciones manualmente.

Código:

Inline bool cninegrid::move chess(unsigned char *array, int way)

{

int cero, cambiar

bool moveok = false

for(zero = 0; zero lt9; zero)

{

if(array[zero] == 0)

Rotura;

}

Punto pnt

pnt.x = cero 3;

pnt.y = int (cero/3);

Cambiar (vía)

{

Caso 0: //on

if(pnt . y 1 lt; 3)

{

Chang =(pnt . y 1)* 3 pto x;

matriz[cero]= matriz[ Chang] ;

matriz[Chang]= 0;

moveok = true

}

Romper;

Caso 1: //abajo

if(pnt . y-1 gt;-1)

{

Chang =(pnt . y-1) * 3 pnt . p>}

Descanso;

Caso 2: //izquierda

if(pnt . x 1 lt; 3)

{

Chang = pnt . y * 3 pnt x 1;

matriz[cero]= matriz[Chang];

matriz[Chang]= 0;

moveok = true

}

Break;

Caso 3: // Correcto

if (pnt .x-1 gt; -1)

{

Chang = pnt . [Chang];

array[Chang]= 0;

moveok = true

}

Romper;

}

if(moveok amp; amp! m_istepcount)

{

m_istepcount;

DWORD temp1, temp2

ArrayToDword(matriz, temp 1) ;

ArrayToDword(m_iTargetChess, temp 2);

if (temp1 == temp2)

{

MessageBox(NULL, " Eres tan inteligente, ¡Lo terminaste tan rápido!", "^_^", 0);

}

}

Volver a moveok

}

En la búsqueda amplia, el índice de matriz del nodo principal se registra en el nodo secundario. Por lo tanto, cuando se obtiene la disposición objetivo, se puede iniciar la búsqueda inversa desde el nodo secundario para obtener la búsqueda óptima. . camino. Utilice la variable m_iPathsize para registrar el número total de pasos.

El código de función específico es:

void cn inegrid::get path (profundidad de la unidad)

{

int now = 0, maxpos = 100;

p>

UINT parentid

if (m_pPathList!=null)

{

Eliminar[]m _ ppath list;

}

m_pPathList = nueva lista de rutas [max pos]

parentid = m_pScanbuf[profundidad]. ScanID

DwordToArray(m_pScanbuf[profundidad]). Lugar, m_pPathList[ahora]. ruta);

while(parentid!= -1)

{

si (ahora == maxpos)

{

maxpos = 10;

lista de rutas * lista de tems = nueva lista de rutas[max pos];

memcpy(temlist, m_pPathList, sizeof(lista de rutas)*( max pos-10));

Eliminar[]m _ ppath list;

m _ pPathList = temlist

}

DwordToArray (m_pScanbuf[idpadre]). Lugar, m_pPathList[ahora]. ruta);

parentid = m_pScanbuf[parentid]. ScanID

}

m _ iPathsize = now

}

La función de demostración de disposición dinámica es la más simple. Para darle al formulario principal la oportunidad de actualizarse a tiempo, se inicia un hilo. Cuando sea necesario actualizar el formulario principal, simplemente use la función Slee (UINT) para pausar el hilo. Código:

Unsigned_ _ stdcall MoveChessThread(LPVOID PPAR am)

{

cningrid * p grid = (cningrid *)PP aram;

RECT Rectángulo;

p gird- gt; m_iStepCount = 0;

* GetClientRect(pg ird- gt; m_hClientWin amp; rect);

p >

for(int I = p gird- gt; m_iPathsize i gt0; i-)

{

memcpy(pg ird- gt; m_iChess, pg ird - gt; m_atleta[i].

ruta, 9);

p gird- gt; m _ istecount

invalidator(pg ird- gt; m _ hClientWin amp; rect, false

<); p>sleep(300);

}

char msg[100];

sprintf(msg, "^_^! ¡Listo!\ r \ The el paso de cálculo toma d milisegundos", p grid- gt; m_iTime);

MessageBox(NULL, msg, "~_~", 0);

p gird-gt; m _ bAutoRun = false

Devuelve 0L;

}

Finalmente, se introduce el principio de la función de búsqueda. Primero, obtenga la matriz fuente y conviértala al tipo DWORD. Compare con el objetivo, si el mismo resultado es diferente, intercambie los datos y la posición espacial, únase al árbol binario y busque el siguiente resultado hasta que no quede ningún siguiente paso. De esta manera, antes de encontrar el resultado objetivo, la función:

bool cninegrid::ComputeFeel()

{

Unsigned char * array = m _ iChess

UINT I;

const int MAXSIZE = 362880

Matriz temporal de caracteres sin firmar[9];

Destino DWORD, fuente, ID de padre = 0, hijo = 1;

ArrayToDword(m_iTargetChess, objetivo);

ArrayToDword(matriz, fuente);

if(fuente==objetivo)

{

Devuelve falso

}

if (m_pScanbuf!=null)

{

eliminar[]m _ pScanbuf;

}

m _ pScanbuf = nuevo Scanbuf[MAXSIZE]

AddTree(fuente, m _ pplace lista;

m_pScanbuf[ 0 ]. Lugar = Fuente;

m_pScanbuf[ 0 ]. ScanID =-1;

reloj _ t Tim = reloj();

while(parentID lt;MAXSIZE ampchild ltMAXSIZE)

{

padre = m_pScanbuf[IDpadre]. Lugar;

for(I = 0; i lt4; i) // 0: arriba, 1: abajo, 2: izquierda, 3: derecha

{

DwordToArray(parent, temparray);

If (MoveChess(temparray, i)) //¿El movimiento fue exitoso?

{

ArrayToDword(temparray, fuente);

If (add tree (fountain, m_pplace list))//Agrega el número de búsquedas.

{

m_pScanbuf[niño].

lugar = fuente;

m_pScanbuf[niño]. ScanID = parentID

If (fountain == target) // ¿Encontraste el resultado?

{

m _ iTime = reloj()-Tim

obtener ruta(niño); //Calcular ruta

FreeTree (m _ pplace lista);

delete[]m _ pScanbuf

m _ pScanbuf = NULL

Devuelve verdadero

}

niño;

}

}

} //Para mí

parentid;

}

m _ iTime = reloj()-Tim;

FreeTree(m _ pplace lista

eliminar[]m _ pScanbuf;

m _ pScanbuf = NULL

Devuelve falso

}

Se presentan las funciones importantes, los siguientes son los resultados de ejecución y la operación; resultados del programa :

ter>