Оптимизировать матричное умножение


9

Эта задача состоит в том, чтобы вычислить наиболее эффективный порядок умножения для произведения нескольких матриц.

Размер матриц указывается в одной строке стандартного ввода. Вы должны вывести на стандартный вывод список целых чисел, указывающий порядок, в котором нужно умножать, чтобы минимизировать общую стоимость умножения.

пример 1

вход

5x6 6x12 12x100 100x7

вывод

3 2 1

Строка ввода будет представлять собой разделенный пробелами список размеров матрицы, каждый из которых представляет собой количество строк, после которых xследует число, а затем число столбцов. Для примера, есть 4 матрицы для умножения вместе (таким образом, 3 суммарных умножения), и, поскольку умножение матриц является ассоциативным, они могут быть выполнены в любом порядке.

На выходе должен быть порядок, в котором нужно выполнять умножения, чтобы минимизировать общую стоимость. Это должен быть разделенный пробелами список целых чисел, представляющих индекс умножения для выполнения следующего. Для N матриц этот список должен содержать числа от 1 до N-1 включительно. Например, вывод 1 3 2 1означает, что вы должны 12x100 * 100x7сначала выполнить умножение, затем 6x12 * 12x7умножение (вторая матрица умножается на результат предыдущего шага), а затем окончательное 5x6 * 6x7умножение.

Умножения матриц всегда будут совместимыми, то есть количество столбцов матрицы будет соответствовать количеству строк последующей матрицы. Предположим, что стоимость умножения двух матриц AxB * BxCравна A*B*C.

Ваш код должен обрабатывать списки до 100 матриц, каждая из которых имеет размер до 999, и делать это в разумные сроки.

пример 2

вход

5x10 10x5 5x15 15x5

вывод

1 3 2

или

3 1 2

пример 3

вход

22x11 11x78 78x123 123x666 666x35 35x97 97x111 111x20 20x50

вывод

2 3 4 5 6 7 8 1

Примечание: для проверки лучшая общая стоимость для трех примеров составляет 9114, 750 и 1466344.

Самый короткий код выигрывает!


Вы уверены в последнем примере? Общая стоимость, указанная моим кодом, составляет 1466344.
Говард

@ Ховард: Да, вы правы, ошибка в моем коде. Исправлена.
Кит Рэндалл

Ответы:


1

Рубин, 176 172 205 символов

Вот еще одна версия (на несколько символов длиннее), которая также будет работать для большого ввода за разумное время.

q=(gets.split<<$_[/\d+$/]).map &:to_i
r=Hash.new{|h,i|h[i]=Hash.new{|h,j|h[j]=1e12;h[j]=i==j ?[0,[]]:(i...j).map{|k|a,c=r[i][k];b,d=r[k+1][j];[a+b+q[i-1]*q[k]*q[j],c+d+[k]]}.min}}
$><<r[1][q.size-1][1]*' '

Первая версия: прямая рекурсивная реализация в Ruby. Это делает полный поиск и, следовательно, может быть медленным на больших входах.

k=->m{m[2]?(1..m.size-2).map{|l|s=k[m[0,l]+m[l+1..-1]];[m[l-1]*m[l]*m[l+1]+s[0],[l]+s[1].map{|u|u<l ?u:u+1}]}.min: [0,[]]}
$><<k[(gets.split<<$_[/\d+$/]).map &:to_i][1]*' '

Часть проблемы заключается в обработке 100 матриц в разумные сроки, чего нет в этом коде.
Кит Рэндалл

@KeithRandall Ах, я не читал это предложение (и мне это не нравится - это очень сильная сдержанность). Я постараюсь найти решение, которое может справиться и с этим делом.
Говард
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.