private void btnPesquisar_Click(object sender, EventArgs e) { if (cbxDestino.SelectedIndex < 0 || cbxOrigem.SelectedIndex < 0) { MessageBox.Show("Por favor, escolha as duas cidades"); return; } if (cbxDestino.Text == cbxOrigem.Text) { MessageBox.Show("As cidade de origem e de destino coincidem"); return; } txtCaminhos.Clear(); Stack <Movimento> movs = null; if (rdbtnBacktracking.Checked) { movs = grafoCaminhos.BacktrackingMelhorCaminho(cbxOrigem.Text, cbxDestino.Text); // obtém o melhor caminho por backtracking } else if (rdbtnDijkstra.Checked) { movs = grafoCaminhos.DijkstraMelhorCaminho(cbxOrigem.Text, cbxDestino.Text); // obtém o melhor caminho por Dijkstra } else if (rdbtnRecursao.Checked) { movs = grafoCaminhos.RecursaoMelhorCaminho(cbxOrigem.Text, cbxDestino.Text); // obtém o melhor caminho por recursão } if (movs != null && movs.Count > 0) // se houver caminho entre as duas cidades { Stack <Movimento> caminhosOrdenados = new Stack <Movimento>(); while (movs.Count > 0) // inverte a pilha de resultados { caminhosOrdenados.Push(movs.Pop()); } Movimento mov = null; int distancia = 0; while (caminhosOrdenados.Count > 0) { mov = caminhosOrdenados.Pop(); txtCaminhos.AppendText(cidades[mov.getCidade()] + " - "); distancia += grafoCaminhos.ConexaoDiretaEntre(cidades[mov.getCidade()], cidades[mov.getSaida()]); } txtCaminhos.AppendText(cidades[mov.getSaida()]); txtCaminhos.AppendText(": " + distancia + "km"); } else { MessageBox.Show("Não foi possível encontrar um caminho entre as cidades especificadas"); } }
/// <summary> /// Overload utilizada por sua versão pública para encontrar recursivamente o melhor caminho /// </summary> /// <param name="cidadeOrigem">Índice da cidade de partida</param> /// <param name="cidadeDestino">Índice da cidade de destino</param> /// <returns>Pilha com todos os trajetos necessários para chegar de uma cidade a outra. Se retornar vazia, não existe caminho entre as duas cidades</returns> protected Stack <Movimento> RecursaoMelhorCaminho(int cidadeOrigem, int cidadeDestino) { double custo = double.MaxValue; Stack <Movimento> ret = new Stack <Movimento>(); vertices[cidadeOrigem].foiVisitado = true; // Evita que suas chamadas filhas voltem de cidade e entrem em loop // Caso haja conexão direta entre a cidade atual e a cidade de destino e esta conexão for melhor que o melhor caminho até agora, // a consideramos o melhor caminho if (adjMatrix[cidadeOrigem, cidadeDestino] != 0) { Movimento m = new Movimento(); m.setValores(cidadeOrigem, cidadeDestino); ret.Push(m); custo = adjMatrix[cidadeOrigem, cidadeDestino]; } for (int saidaAtual = 0; saidaAtual < numVerts; saidaAtual++) // Testa o melhor caminho por todas as saídas { if (adjMatrix[cidadeOrigem, saidaAtual] == 0) // Não há saída da cidade de origem pela saidaAtual { continue; } // Nunca passa duas vezes pelo mesmo local. Serve como condição de saída, já que, caso todas as saídas já tenham sido visitadas, // o método não se chama novamente. if (vertices[saidaAtual].foiVisitado) { continue; } if (saidaAtual == cidadeDestino) // Esta condição já fora tratada fora do for { continue; } Stack <Movimento> caminhoEncontrado = RecursaoMelhorCaminho(saidaAtual, cidadeDestino); if (caminhoEncontrado.Count <= 0) // Caso não encontrou caminho, a saída nem precisa ser avaliada { continue; } // Avalia a eficácia do caminho Stack <Movimento> aux = new Stack <Movimento>(); double custoAtual = 0; while (caminhoEncontrado.Count > 0) { Movimento m = caminhoEncontrado.Pop(); custoAtual += adjMatrix[m.getCidade(), m.getSaida()]; aux.Push(m); } custoAtual += adjMatrix[cidadeOrigem, saidaAtual]; // Se o caminho encontrado for o melhor até agora, o armazenamos if (custoAtual < custo) { ret.Clear(); // Adiciona o trajeto da cidade de origem ate a saída onde se inicia o caminho Movimento m = new Movimento(); m.setValores(cidadeOrigem, saidaAtual); ret.Push(m); while (aux.Count > 0) // Restaura o caminho encontrado, em ordem, na pilha de retorno { ret.Push(aux.Pop()); } custo = custoAtual; } } vertices[cidadeOrigem].foiVisitado = false; // Faz isso para permitir que outras chamadas (anteriores) utilizem aquele vértice return(ret); }
/// <summary> /// Busca o melhor caminho possível entre duas cidades usando Backtracking iterativo /// </summary> /// <param name="cidadeOrigem">Cidade de partida</param> /// <param name="cidadeDestino">Cidade destino</param> /// <returns>Pilha com todos os trajetos necessários para chegar de uma cidade a outra. Se retornar nula, não existe caminho entre as duas cidades</returns> public Stack <Movimento> BacktrackingMelhorCaminho(string cidadeOrigem, string cidadeDestino) { for (int i = 0; i < numVerts; i++) { vertices[i].foiVisitado = false; } Stack <Movimento> result = new Stack <Movimento>(); Stack <Movimento> p = new Stack <Movimento>(); bool achou = false; int cidadeAtual; int saidaAtual = 0; cidadeAtual = IndiceDe(cidadeOrigem); while (!(cidadeAtual == IndiceDe(cidadeOrigem) && saidaAtual == numVerts && p.Count <= 0)) { // só sai do while quando tiver tentado todos os caminhos while (saidaAtual < numVerts && !achou) { if (adjMatrix[cidadeAtual, saidaAtual] == 0) // se não houver conexão entre a cidadeAtual e a saidaAtual { saidaAtual++; // tenta a próxima saída } else if (vertices[saidaAtual].foiVisitado) // Se já tentamos a saidaAtual { saidaAtual++; // tenta a próxima saída } else if (saidaAtual == IndiceDe(cidadeDestino)) // Se chegamos aonde queríamos { Movimento movim = new Movimento(); movim.setValores(cidadeAtual, saidaAtual); p.Push(movim); achou = true; // achamos uma das possíveis rotas } else { Movimento movim = new Movimento(); movim.setValores(cidadeAtual, saidaAtual); p.Push(movim); // adicionamos o último movimento vertices[cidadeAtual].foiVisitado = true; cidadeAtual = saidaAtual; // vamos para a saidaAtual saidaAtual = 0; // procuramos novamente por novas saídas } } if (!achou) { if (p.Count > 0) { Movimento movim = (Movimento)p.Pop(); saidaAtual = movim.getSaida(); cidadeAtual = movim.getCidade(); movim = null; saidaAtual++; } } else // se achou um novo caminho, mede sua eficiência e se for melhor, o coloca na pilha de resultado { Stack <Movimento> aux = new Stack <Movimento>(); double distanciaI = 0; if (result.Count == 0) { distanciaI = double.MaxValue; } while (result.Count > 0) { Movimento mov = result.Pop(); distanciaI += adjMatrix[mov.getCidade(), mov.getSaida()]; aux.Push(mov); } while (aux.Count > 0) { result.Push(aux.Pop()); } double criterioNovo = 0; while (p.Count > 0) { Movimento mov = p.Pop(); criterioNovo += adjMatrix[mov.getCidade(), mov.getSaida()]; aux.Push(mov); } while (aux.Count > 0) { p.Push(aux.Pop()); } if (criterioNovo <= distanciaI) { aux = new Stack <Movimento>(); result = new Stack <Movimento>(); while (p.Count > 0) { aux.Push(p.Pop()); } while (aux.Count > 0) { Movimento mov = aux.Pop(); result.Push(mov); p.Push(mov); } } if (p.Count > 0) { Movimento movim = (Movimento)p.Pop(); saidaAtual = movim.getSaida(); cidadeAtual = movim.getCidade(); movim = null; saidaAtual++; } achou = false; } } return(result); }