【问题标题】:Branch and bound using Perl使用 Perl 进行分支和绑定
【发布时间】:2023-03-31 20:56:01
【问题描述】:

我有一个问题,我找不到答案。我正在使用 Perl。我的输入是一个对称成本矩阵,有点像 TSP。

我想知道位于我的边界(即 10)之下的所有解。

这是我的矩阵:

-   B   E   G   I   K   L   P   S   
B   -   10  10  2   10  10  10  10  
E   10  -   2   10  10  10  1   10  
G   10  2   -   10  2   3   3   3   
I   2   10  10  -   4   10  10  2   
K   10  10  2   4   -   10  10  3   
L   10  10  3   10  10  -   2   2   
P   10  1   3   10  10  2   -   10  
S   10  10  3   2   3   2   10  -   

有人知道如何实现分支定界算法来解决这个问题吗?目前,我确实将矩阵中的每 10 个替换为“-”。


到目前为止我做了什么:

 @verwbez = ( ["-", B, E, G, I, K, L, P, S], 
              [B,"-", 10, 10, 2, 10, 10, 10, 10], 
              [E, 10, "-", 2, 10, 10, 10, 1, 10], 
              [G, 10, 2, "-", 10, 2, 3, 3, 3], 
              [I, 2, 10, 10, "-", 4, 10, 10, 2], 
              [K, 10, 10, 2, 4, "-", 10, 10, 3], 
              [L, 10, 10, 3, 10, 10, "-", 2, 2], 
              [P, 10, 1, 3, 10, 10, 2, "-", 10], 
              [S, 10, 10, 3, 2, 3, 2, 10, "-"]);
for ($i=0;$i<=$#verwbez;$i++) {
    for ($j=0; $j<=$#{$verwbez[$i]};$j++) {
        while ($verwbez[$i][$j] >=7) { 
            $verwbez[$i][$j] = "-";
        }
    }
} 

基本上只是改变矩阵,每10个被替换为“-”。现在我想找到所有低于 10 的解决方案,并且包含 4 个总是两个城市连接在一起的地区。但不幸的是,我不知道如何继续/开始......

【问题讨论】:

  • 解决方案是什么样的,如何使用成本矩阵来评估它?对于 TSP,它将是一个有序序列,因为成本指的是路径,例如BISLPEGK。你的问题也是这样,还是你在构建路径以外的东西?
  • 我忘了说。字母是城市。始终应将两个链接到导致成本的“区域”。所以最终应该总是有 4 个区(包括 8 个城市)一起计算,最大成本为 10。每个城市应该只提到一次/解决方案。
  • 所以它就像一个分段的TSP?解决方案可能如下所示:['BI', 'SL', "PE', 'KG'] (cost 7) 。 . .对吗?
  • 您遇到的具体问题是什么?你试过什么吗?
  • 好的,我意识到我的最后一步,改变矩阵,并不是真正需要的,所以我跳过了。反过来,我希望它逐步通过矩阵并找到条目

标签: perl branch-and-bound


【解决方案1】:

您不太可能有人为您实现Branch and Bound 算法。但是,以下 stackoverflow 帖子 TSP - branch and bound 包含一些指向一些有用资源的链接:

  1. Optimal Solution for TSP using Branch and Bound
  2. B&amp;B Implementations for the TSP - 第 1 部分:包含部分旅行的节点的解决方案 约束
  3. B&amp;B Implementations for the TSP - 第 2 部分:具有许多廉价节点的单线程解决方案

由于您似乎是 perl 新手,我们可以给您一些快速提示

  1. 始终在每个 perl 脚本的顶部包含 use strict;use warnings
  2. 在创建递增的for 循环时使用range operator ..
  3. 您的while 循环实际上应该是一个if 语句。
  4. 要增加样式,请考虑在初始化混合字/数字数组时使用 qw(),尤其是因为它可以让您轻松对齐多维数组的元素
  5. 对于此类项目,您的第一个目标应该是创建一种方法以以可读格式输出多维数组,以便您可以观察和验证所做的更改。

所有这些都带来了以下变化:

use strict;
use warnings;

my @verwbez = (
    [qw(-  B  E  G  I  K  L  P  S )],
    [qw(B  -  10 10 2  10 10 10 10)],
    [qw(E  10 -  2  10 10 10 1  10)],
    [qw(G  10 2  -  10 2  3  3  3 )],
    [qw(I  2  10 10 -  4  10 10 2 )],
    [qw(K  10 10 2  4  -  10 10 3 )],
    [qw(L  10 10 3  10 10 -  2  2 )],
    [qw(P  10 1  3  10 10 2  -  10)],
    [qw(S  10 10 3  2  3  2  10 - )],
); 

for my $i (0 .. $#verwbez) {
    for my $j (0 .. $#{$verwbez[$i]}) {
        if ($verwbez[$i][$j] =~ /\d/ && $verwbez[$i][$j] >= 7) {
            $verwbez[$i][$j] = ".";
        }
    }
}

for (@verwbez) {
    for (@$_) {
        printf "%2s ", $_;
    }
    print "\n";
}

输出:

 -  B  E  G  I  K  L  P  S
 B  -  .  .  2  .  .  .  .
 E  .  -  2  .  .  .  1  .
 G  .  2  -  .  2  3  3  3
 I  2  .  .  -  4  .  .  2
 K  .  .  2  4  -  .  .  3
 L  .  .  3  .  .  -  2  2
 P  .  1  3  .  .  2  -  .
 S  .  .  3  2  3  2  .  -

请注意,B 附近只有 1 个城市。因此,如果目标是解决 TSP,那么就没有简单的解决方案。但是,鉴于只有 8 个城市和 (n-1)!循环排列。这给了我们 5,040 个排列,因此使用蛮力完全可以找到成本最低的解决方案。

use strict;
use warnings;

use Algorithm::Combinatorics qw(circular_permutations);

my @verwbez = ( ... already defined ... ); 

# Create a cost between two cities hash:
my %cost;
for my $i (1..$#verwbez) {
    for my $j (1..$#{$verwbez[$i]}) {
        $cost{ $verwbez[$i][0] }{ $verwbez[0][$j] } = $verwbez[$i][$j] if $i != $j;
    }
}

# Determine all Routes and their cost (sorted)
my @cities = keys %cost;
my @perms = circular_permutations(\@cities);
my @cost_with_perm = sort {$a->[0] <=> $b->[0]} map {
    my $perm = $_;
    my $prev = $perm->[-1];
    my $cost = 0;
    for (@$perm) {
        $cost += $cost{$_}{$prev};
        $prev = $_
    }
    [$cost, $perm]
} @perms;

# Print out lowest cost routes:
print "Lowest cost is: " . $cost_with_perm[0][0] . "\n";
for (@cost_with_perm) {
    last if $_->[0] > $cost_with_perm[0][0];
    print join(' ', @{$_->[1]}), "\n";
}

最终,这种设置只有 2 个成本最低的解决方案,它们是彼此的镜像,这是有道理的,因为我们没有在循环排列中按方向过滤。我故意不说明他们在这里是什么。

【讨论】:

  • 哇,非常感谢!是的,我对 Perl 和编程都是新手。了解如何解决某个问题对我很有帮助,因为我还不习惯这种语言。但我希望这种情况会很快改变。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多