Eu comecei com uma tabela de todas as distâncias entre as capitais departamentais. Depois, uma função que percorre recursivamente todas as possibilidades partindo de uma cidade específica. Este não é o problema do caixeiro viajante: não é preciso terminar no mesmo lugar.
Para acelerar a busca, o código corta os ramos da árvore de busca que forem maiores que a menor distância já encontrada. Então, o programa vai acelerando com o tempo. Mesmo assim, ele levou um dia inteiro para encontrar o melhor caminho a partir de Artigas.
A solução encontrada tem 1927km. Ou seja, o projeto é viável, mesmo para ser executado em uma semana.
A tabela abaixo tem todos os passos e as distâncias percorridas em cada um.
Artigas | |
Rivera | 183 |
Tacuarembó | 111 |
Melo | 204 |
Treinta y Tres | 113 |
Rocha | 172 |
Maldonado | 85 |
Minas | 75 |
Montevideo | 122 |
Canelones | 46 |
Florida | 52 |
Durazno | 85 |
Trindad | 41 |
San José | 95 |
Colonia | 108 |
Mercedes | 176 |
Fray Bentos | 31 |
Paysandú | 110 |
Salto | 118 |
#!/usr/bin/perl
use strict;
use experimental 'smartmatch';
$|=1;
my $capitals={
0=>'Artigas',
1=>'Canelones',
2=>'Colonia',
3=>'Durazno',
4=>'Florida',
5=>'Fray Bentos',
6=>'Maldonado',
7=>'Melo',
8=>'Mercedes',
9=>'Minas',
10=>'Montevideo',
11=>'Paysandú',
12=>'Rivera',
13=>'Rocha',
14=>'Salto',
15=>'San José',
16=>'Tacuarembó',
17=>'Treinta y Tres',
18=>'Trinidad'
};
my $distances=[
[0,555,611,418,503,435,748,392,435,711,601,325,183,671,207,580,211,503,459],
[555,0,145,137,52,268,155,378,237,131,46,332,455,220,450,47,344,282,151],
[611,145,0,218,178,207,301,507,176,276,177,286,549,360,404,108,429,427,176],
[418,137,218,0,85,201,298,418,170,273,183,229,318,363,348,136,207,424,41],
[503,52,178,85,0,286,209,329,255,184,98,318,403,274,437,88,292,355,126],
[435,268,207,201,286,0,422,622,31,395,309,110,452,483,228,220,341,546,160],
[748,155,301,298,209,422,0,325,391,75,134,487,572,85,605,202,509,212,301],
[392,378,507,418,329,622,325,0,590,276,387,435,262,285,428,407,204,113,460],
[435,237,176,170,255,31,391,590,0,363,278,110,452,452,228,189,341,415,129],
[711,131,276,273,184,395,75,276,363,0,122,463,604,132,582,182,484,164,276],
[601,46,177,183,98,309,134,387,278,122,0,378,501,210,496,93,390,286,188],
[325,332,286,229,318,110,487,435,110,463,378,0,342,553,118,285,231,614,190],
[183,455,549,318,403,452,572,262,452,604,501,342,0,541,335,473,111,373,359],
[671,220,360,363,274,483,85,285,452,132,210,553,541,0,672,272,490,172,366],
[207,450,404,348,437,228,605,428,228,582,496,118,335,672,0,403,224,534,309],
[580,47,108,136,88,220,202,407,189,182,93,285,473,272,403,0,353,327,95],
[211,344,429,207,292,341,509,204,341,484,390,231,111,490,224,353,0,320,248],
[503,282,427,424,335,546,212,113,514,164,286,614,373,172,534,327,320,0,427],
[459,151,176,41,126,160,301,460,129,276,188,190,359,366,309,95,248,427,0]
];
sub print_path {
my $distance=shift;
my $marker=shift;
my @path=@_;
my @names=map { $capitals->{$_} } @path;
print "$distance km $marker ";
print join '->', @names;
print "\n";
}
my $limit=3_000;
sub run {
my $capital=shift;
my $distance=shift||0;
my @path=@_;
if(scalar(@path)==18) {
$limit=$distance if $distance<$limit;
print_path($distance, '*', @path, $capital);
} else {
for my $c (0..18) {
if (!($c~~@path) && $c!=$capital) {
my $d=$distances->[$capital]->[$c];
run($c, $distance+$d, @path, $capital) if ($d+$distance)<$limit;
}
}
}
}
run(0);
A função run() recebe o índice de uma cidade e recursivamento adiciona todas as outras, uma a uma, até ter um caminho completo. Mas ela aborta qualquer caminho que ultrapasse o valor de $limit, além de atualizar $limit quando encontra um caminho menor.
Nenhum comentário:
Postar um comentário