Repository navigation
Expand file tree
/
Copy pathBranchNBoundTSP.java
More file actions
372 lines (310 loc) · 13.6 KB
/
Copy pathBranchNBoundTSP.java
File metadata and controls
372 lines (310 loc) · 13.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
/*
Pucminas - Ciência da Computação - Coração Eucarístico
PAA - Manhã
Larissa Gomes Domingues
Pedro Henrique Lima Carvalho
Trabalho Branch and Bound e Backtracking
Código de Branch and Bound - Traveling Salesman Problem
*/
//Dependencias
import java.util.Scanner;
import java.util.ArrayList;
class Grafo{
public static final int INFINITO = 99999;
public int[][] matrizAdj;
public int numVertices;
// Construtor
// @param int p_numVertices
public Grafo(int p_numVertices){
this.numVertices = p_numVertices;
this.initMatriz();
}
/* Método para adicionar aresta entre vértices 1 e 2
* @param int vert1, int vert2, int val
*/
public void adicionarAresta(int vert1, int vert2, int val){
this.matrizAdj[vert1][vert2] = val;
}
public void printGrafo(){
System.out.print(" ");
for(int i = 0; i < this.numVertices; i++)
System.out.print(i + " ");
System.out.println("");
for(int i = 0; i < this.numVertices; i++){
System.out.print(i + " ");
for(int j = 0; j < this.numVertices; j++){
System.out.print(this.matrizAdj[i][j] + " ");
}
System.out.println("");
}
}
/* Método para inicializar matriz de adjacência
* que irá representar o grafo
*/
private void initMatriz(){
this.matrizAdj = new int[this.numVertices][this.numVertices];
//Inicializando grafo sem arestas
for(int i = 0; i < this.numVertices; i++){
for(int j = 0; j < this.numVertices; j++)
this.matrizAdj[i][j] = INFINITO;
}
}
};
/* Classe para representar nós da árvore
* para encontrar o resultado utilizando a abordagem
* Branch and Bound
*/
class No{
public int[][] matrizReduzida;
public int[] caminho;
public int numVertices, reducao, atual, anterior;
// Construtor vazio
public No(){
this.reducao = Grafo.INFINITO;
}
/* Construtor Nos intermediários e folhas
* @param int p_numVertices, int[][] p_matrizAdj, int[] p_caminho, int p_atual, int p_anterior
*/
public No(int p_numVertices, int[][] p_matrizAdj, int[] p_caminho, int p_atual, int p_anterior){
this.numVertices = p_numVertices;
this.reducao = 0;
this.caminho = p_caminho;
this.atual = p_atual;
this.anterior = p_anterior;
// Inicializar matriz de redução e realizar calculo de redução
this.initMatriz(p_matrizAdj, p_atual, p_anterior);
}
/* Construtor No raiz
* @param int p_numVertices, int[][] p_matrizAdj, int[] p_caminho, int p_atual
*/
public No(int p_numVertices, int[][] p_matrizAdj, int[] p_caminho, int p_atual){
this.numVertices = p_numVertices;
this.reducao = 0;
this.caminho = p_caminho.clone();
this.atual = p_atual;
// Inicializar matriz de redução e realizar calculo de redução
this.initMatriz(p_matrizAdj);
}
public void printMatriz(){
System.out.print(" ");
for(int i = 0; i < this.numVertices; i++)
System.out.print(i + " ");
System.out.println("");
for(int i = 0; i < this.numVertices; i++){
System.out.print(i + " ");
for(int j = 0; j < this.numVertices; j++){
if(this.matrizReduzida[i][j] != Grafo.INFINITO)
System.out.print(this.matrizReduzida[i][j] + " ");
else
System.out.print("I ");
}
System.out.println("");
}
}
public void printNo(){
System.out.print("Menor caminho: \n");
System.out.print(" 0");
for(int i = 1; i < this.numVertices; i++)
System.out.print(" - " + this.caminho[i]);
System.out.println("\nSoma dos pesos = " + this.reducao);
}
/* Método para inicializar matriz de redução e calcular redução -> No Raiz
* @param int[][] matrizAdj
*/
private void initMatriz(int[][] matrizAdj){
this.matrizReduzida = new int[this.numVertices][this.numVertices];
// Copiando matriz
for(int i = 0; i < this.numVertices; i++){
for(int j = 0; j < this.numVertices; j++)
this.matrizReduzida[i][j] = matrizAdj[i][j];
}
// Redução por linha
reduzirLinha();
// Redução por coluna
reduzirColuna();
}
/* Método para inicializar matriz de redução e calcular redução -> Nos
* folha e intermediários
* @param int[][] matrizAdj, int p_atual, int p_anterior
*/
private void initMatriz(int[][] matrizAdj, int p_atual, int p_anterior){
this.matrizReduzida = new int[this.numVertices][this.numVertices];
// Copiando matriz
for(int i = 0; i < this.numVertices; i++){
for(int j = 0; j < this.numVertices; j++)
if(j != p_atual && i != p_anterior)
this.matrizReduzida[i][j] = matrizAdj[i][j];
else // linha p_atual e coluna p_anterior = inifinito -> excluir possíveis caminhos
this.matrizReduzida[i][j] = Grafo.INFINITO;
}
this.matrizReduzida[p_atual][p_anterior] = Grafo.INFINITO;
// Redução por linha
reduzirLinha();
// Redução por coluna
reduzirColuna();
}
/* Método para reduzir linhas de matrizReduzida
*/
private void reduzirLinha(){
// Variável para armazenar menor valor de cada linha
int menorLinha = Grafo.INFINITO;
for(int i = 0; i < this.numVertices; i++){
// Encontrar menor valor de linha i
for(int j = 0; j < this.numVertices; j++)
if(menorLinha > this.matrizReduzida[i][j])
menorLinha = this.matrizReduzida[i][j];
// Reduzir menor valor de todos elementos da linha i
for(int j = 0; j < this.numVertices; j++){
if(this.matrizReduzida[i][j] != Grafo.INFINITO) // Não reduzir elementos infinitos
this.matrizReduzida[i][j] -= menorLinha;
}
// Redução = Redução + menor elemento da linha i
if(menorLinha != Grafo.INFINITO) // Não considerar redução de elementos infinitos
this.reducao += menorLinha;
// Limpar menor elemento para próxima iteração
menorLinha = Grafo.INFINITO;
}
}
/* Método para reduzir colunas de matrizReduzida
*/
private void reduzirColuna(){
// Variável para armazenar menor valor de cada coluna
int menorColuna = Grafo.INFINITO;
for(int i = 0; i < this.numVertices; i++){
// Encontrar menor valor de coluna i
for(int j = 0; j < this.numVertices; j++)
if(menorColuna > this.matrizReduzida[j][i])
menorColuna = this.matrizReduzida[j][i];
// Reduzir menor valor de todos elementos da coluna i
for(int j = 0; j < this.numVertices; j++){
if(this.matrizReduzida[j][i] != Grafo.INFINITO)
this.matrizReduzida[j][i] -= menorColuna; // Não reduzir elementos infinitos
}
// Redução = Redução + menor elemento da coluna i
if(menorColuna != Grafo.INFINITO) // Não considerar redução de elementos infinitos
this.reducao += menorColuna;
// Limpar menor elemento para próxima iteração
menorColuna = Grafo.INFINITO;
}
}
}
/*
* Classe Principal - BranchNBoundTSP
*/
public class BranchNBoundTSP{
/* Método recursivo para fazer busca em profundidade na árvore de possíveis
* soluções para o problema de caixeiro viajante de um grafo.
* @param No pai, ArrayList<Integer> naoVisitados, int atual, int anterior,
* int[] caminho, int nivel, No menorCaminhoAtual
* @return No -> menor caminho para candidato a solução recebido como parâmento
*/
public static No TSPRec(No pai, ArrayList<Integer> naoVisitados, int atual, int anterior,
int[] caminho, int nivel, No menorCaminhoAtual){
No aux;
// Inciando No de menor caminho como vazio
No menorCaminho = new No();
int caminhoAtual[] = caminho.clone();
// Adicionando vertice atual ao vetor de caminho
caminhoAtual[nivel] = atual;
// Iniciando No atual da árvore de possíveis soluções
No n = new No(pai.numVertices, pai.matrizReduzida, caminhoAtual, atual, anterior);
// Calculo da redução -> A redução irá sinalizar o menor caminho possível
// para esse estado, o caminho final poderá ser maior que a redução
n.reducao = n.reducao + pai.reducao + pai.matrizReduzida[anterior][atual];
// Se array de não visitados estiver vazio -> No atual = folha
// Resultado para o caminho atual foi encontrado
if(naoVisitados.isEmpty()){
// Se menorCaminho calculado pelo No atual < menor caminho atual
// atualizar menorCaminho atual
return menorCaminho = menorCaminhoAtual.reducao < n.reducao ? menorCaminhoAtual : n;
} else{
// Se menor caminho possível calculado pela redução for menor que
// algum menor caminho já encontrado -> quebrar recursão
if(n.reducao > menorCaminhoAtual.reducao)
return n;
// Número de vértices ainda não visitados
int numVerticesRestantes = n.numVertices - nivel - 1;
// Visitar Nos não visitados na árvore de possíveis soluções
for(int i = 0; i < numVerticesRestantes; i++){
// Escolher um vértice não visitado
int prox = naoVisitados.remove(0);
// Chamando método recursivo para solucionar Caixeiro viajante
aux = TSPRec(n, naoVisitados, prox, atual, caminhoAtual, nivel + 1, menorCaminhoAtual);
// Se menorCaminho calculado pelo No atual < menor caminho atual
// atualizar menorCaminho atual
menorCaminho = menorCaminho.reducao < aux.reducao ? menorCaminho : aux;
// Adicionar vértice escolhido em novamente em naoVistados, para
// que eles seja visitado em próximos nós
naoVisitados.add(prox);
}
}
return menorCaminho;
}
/* Método para resolver o problema do caixeiro viajante em
* um grafo a partir de uma abordagem que utiliza um algoritmo
* Branch and Bound
* @param Grafo g
* @return No contendo menor caminho
*/
public static No TSP(Grafo g){
// Inciando No de menor caminho como vazio
No menorCaminho = new No();
No aux;
// Array para armazenar caminhos
int[] caminhoAtual = new int[g.numVertices + 1];
// Vertice inicial -> 0
caminhoAtual[0] = 0;
// Controle de vertices não visitados
ArrayList<Integer> naoVisitados = new ArrayList();
// Inicando vetor de vertices de vértices não visitados
for(int i = 1; i < g.numVertices; i++)
naoVisitados.add(i);
// Iniciando No raiz
No n = new No(g.numVertices, g.matrizAdj, caminhoAtual, 0);
// Variável para armzenar próximo vértice a ser visitado na estrutura de
// árvore que enumera possíveis soluções
int prox;
for(int i = 0; i < g.numVertices; i++) {
// Escolher um vértice não visitado
prox = naoVisitados.remove(0);
// Chamando método recursivo para solucionar Caixeiro viajante
aux = TSPRec(n, new ArrayList(naoVisitados), prox, 0, caminhoAtual, 1, menorCaminho);
// Se menorCaminho calculado pelo método recursivo < menor caminho atual
// atualizar menorCaminho atual
menorCaminho = menorCaminho.reducao < aux.reducao ? menorCaminho : aux;
// Adicionar vértice escolhido em novamente em naoVistados, para
// que eles seja visitado em próximos nós
naoVisitados.add(prox);
}
return menorCaminho;
}
/*
main
*/
public static void main(String[] args){
Scanner reader = new Scanner(System.in);
int numVertices, numAretas, v1, v2, valor;
System.out.print("Número de vértices: ");
numVertices = reader.nextInt();
System.out.print("Número de arestas: ");
numAretas = reader.nextInt();
// Criando grafo
Grafo g = new Grafo(numVertices);
// Repetição para adicionar arestas no grafo g
for(int i = 0; i < numAretas; i++){
System.out.println("Aresta [" + (i+1) + "]");
// Leitura vértice 1 da aresta i
System.out.print("Vértice 1: ");
v1 = reader.nextInt();
// Leitura vértice 2 da aresta i
System.out.print("Vértice 2: ");
v2 = reader.nextInt();
// Leitura peso da aresta v1 - v2
System.out.print("Peso: ");
valor = reader.nextInt();
// Adicionando aresta entre v1 e v2
g.adicionarAresta(v1, v2, valor);
}
TSP(g).printNo();
}
}