You’ve already had the gist of your answer: build a recursive algorithm.
If you choose to use a linked list, the advantage is that the removal of items will be quite efficient. Thus, it is possible to construct with some ease the following algorithm:
Construct a list of read pieces. Use a data structure that contains for each piece the values on the left and right (using a struct
, for example).
In the main program, make a loop (a for
) to iterate on all elements of this list. The idea is that you will test each one of them to see if there is a solution that begins with such a piece. There are actually two tests per piece: one with it starting at the left (that is, connecting at the right number), and one with it starting at the right (that is, connecting at the left number).
Inside this loop, choose the current tile as "first" and one of its numbers to start. Then create a sublist from the removal of the first chosen piece for the test. Using a linked list this removal is efficient: clone the original list and remove the current domino from the loop. This sublist will be used to limit the searches in the recursive call.
Call a function (name solucao
, for example) that will recursively process the answer you want. Pass to this created sublist function (that is, containing only the next possible dominoes to be connected), the first piece (already chosen) and the number by which it will connect. This function will internally do something similar to the previous steps of the main program: it will scroll through the received list (which is already a sub-list of your previous call! ), trying to find an item that connects to the number received as parameter. If it does not find it is a sign that there is no solution for this number/connection. Therefore, it can return an indicative return of failure. If she finds a piece that connects, she’ll need to keep searching for the other items.
So, if you find a connection, just create a new sublist (removing from the "original" list - which, remember, was already a sublist - this next piece found) and recursively search for another piece that connects. The idea of recursion is precisely the deep search in the connection possibilities tree. If the search goes down and does not find a solution, the stacked calls will return until you find a solution (if it exists). If this new recursive call solucao
find an answer, you found it and just match the current piece, with the next piece found to build part of the answer. If not, there is no solution.
Obs. Vc can do recursive function solucao
already return a string with the solution or an empty string (""
) if I can’t fix it. Thus, its indication of "has solution" is to return the strings with the current piece concatenated with the next piece, and the indication of "has no solution" is to return the empty string.
As I don’t have time to prepare a pure C example (which also shouldn’t be done, since your question is probably a school project that you must learn to do by yourself), I just prepared an example in C++. It’s not for you to copy and paste, obviously, but it might help you understand a little more the simple algorithm proposal.
Remember that in C you will need to implement some of the things
that there are facilitated by the use of Standard Library of C++
as the linked list (where I use the std::vector
), cloning and
removal of elements (where I use the allocation operator and the
algorithms std::vector::erase
and std::remove
), the data structure
domino (that I used a class
, that you will certainly use
as a struct
), etc..
Anyway, here’s the code:
#include <vector>
#include <algorithm>
#include <iostream>
#include <string>
using namespace std;
class Domino
{
public:
unsigned short e; // Número na esquerda
unsigned short d; // Número na direita
// Construtor padrão
Domino()
{
e = 0;
d = 0;
}
// Construtor com os parâmetros
Domino(unsigned short e, unsigned short d)
{
this->e = e;
this->d = d;
}
// Operador de igualdade (pra permitir a comparação usada nos métodos erase/remove)
bool operator==(const Domino &oOutro)
{
return this->e == oOutro.e && this->d == oOutro.d;
}
// Pra facilitar a geração da string da peça
string toString(unsigned int iNaDireita)
{
string s;
if (iNaDireita == e)
s = to_string(d) + to_string(e);
else
s = to_string(e) + to_string(d);
return s;
}
};
typedef vector<Domino> Dominos;
// Função de procura recursiva por conexoes a partir de uma peça e número dados
string solucao(Dominos vPecas, Domino oPeca, unsigned short iNumero)
{
Domino oProxima;
unsigned short iProximo;
bool bFound = false;
// Procura por uma peça qualquer que encaixe na peça + número dados
for (unsigned int i = 0; i < vPecas.size(); i++)
{
Domino oAtual = vPecas[i];
if (oAtual.e == iNumero || oAtual.d == iNumero)
{
oProxima = oAtual;
iProximo = (oAtual.e == iNumero) ? oAtual.d : oAtual.e; // !!OBSERVAÇÃO!!
bFound = true;
break;
}
}
// Se encontrou alguma peça que se encaixa, checka a solução
if (bFound)
{
// Se só existe ela e ela encaixa, pronto! Achou-se a solução!
if (vPecas.size() == 1)
return oPeca.toString(iNumero) + "|" + oProxima.toString(iProximo);
// Mas se existem mais peças, continua a busca recursivamente...
else
{
Dominos vOutros = vPecas; // Clona a lista
// Remove a próxima peça do clone, criando a sublista
vOutros.erase(remove(vOutros.begin(), vOutros.end(), oProxima));
// Procura recursivamente por outra, considerando agora a próxima peça como "primeira"
// O número para a nova conexão deve ser *necessariamente* o oposto àquele que encaixou,
// o que foi decidido anteriormente onde está marcado com o comentário "!!OBSERVAÇÃO!!"
string s = solucao(vOutros, oProxima, iProximo);
if (s.length() == 0)
return ""; // Não tem solução porque há mais peças, mas elas não encaixam
else
return oPeca.toString(iNumero) + "|" + s; // Tem solução! Monta e devolve!
}
}
else
return ""; // Não tem solução porque não há peças que encaixam na peça recebida como parâmetro
}
int main()
{
Dominos vPecas;
/*vPecas.push_back(Domino(1, 3));
vPecas.push_back(Domino(1, 5));
vPecas.push_back(Domino(3, 2));*/
vPecas.push_back(Domino(3, 4));
vPecas.push_back(Domino(2, 5));
vPecas.push_back(Domino(3, 6));
vPecas.push_back(Domino(4, 5));
// Tenta uma solução com cada uma das peças, posicionada à esquerda ou à direita
string sSolucao;
for (unsigned int i = 0; i < vPecas.size(); i++)
{
Domino oPrimeira = vPecas[i];
Dominos vOutros = vPecas; // Clona a lista
// Remove da lista clonada a peça usada como primeira
vOutros.erase(remove(vOutros.begin(), vOutros.end(), oPrimeira));
// Tenta uma solução com a peça colocada à esquerda
sSolucao = solucao(vOutros, oPrimeira, oPrimeira.d);
// Se encontrou, ótimo!
if (sSolucao.length() != 0)
break;
// Senão, tenta com a peça colocada à direita
else
{
sSolucao = solucao(vOutros, oPrimeira, oPrimeira.e);
if (sSolucao.length() != 0)
break;
}
}
// verifica se algo foi devolvido. Se não, não há solução
if (sSolucao.length() == 0)
sSolucao = "Solucao nao encontrada.";
// Imprime a resposta
cout << "Resposta do algoritmo:" << endl;
cout << sSolucao << endl;
return 0;
}
This code produces the following result for the parts 3 4
, 2 5
, 3 6
and 4 5
(I used in place of your example):
Resposta do algoritmo:
25|54|43|36
That is, your doubt is the algorithm. Right?
– Luiz Vieira
Yeah, I don’t know where it’s going.
– Hilbert Digênio