Suma matricial no superpuesta

25

Suma matricial no superpuesta

Dadas k matrices de longitud n , genere la suma máxima posible utilizando un elemento de cada matriz, de modo que no haya dos elementos del mismo índice. Se garantiza que k <= n.

Entrada

Una lista no vacía de matrices no enteras de enteros.

Salida

Un entero que representa la suma máxima.

Ejemplos

Input -> Output
[[1]] -> 1
[[1, 3], [1, 3]] -> 4
[[1, 4, 2], [5, 6, 1]] -> 9
[[-2, -21],[18, 2]] -> 0
[[1, 2, 3], [4, 5, 6], [7, 8, 9]] -> 15
[[1, 2, 3, 4], [5, 4, 3, 2], [6, 2, 7, 1]] -> 16
[[-2, -1], [-1, -2]] -> -2
Quintec
fuente
55
Dato curioso de la matemática: para las matrices cuadradas, esta es la matriz permanente sobre el semiring tropical que utiliza las operaciones (max, +) en lugar de (+, *).
xnor

Respuestas:

9

Jalea , 10 6 bytes

ZŒ!ÆṭṀ

Pruébalo en línea!

(4 bytes salvados por @Dennis, quien señaló que la jalea tenía una "suma de diagonal principal" incorporado que estaba. No esperaba que tuviera uno de esos; la solución anterior implementa la operación sin necesidad de utilizar la orden interna La operación en cuestión,. Æṭ, se define como "traza", pero la traza solo se define para matrices cuadradas; Jelly implementa una generalización a matrices rectangulares también.)

La mejora con respecto a las otras respuestas se debe principalmente a un algoritmo más simple (por lo tanto, más difícil de expresar); Este programa se escribió originalmente en Brachylog v2 ({\p\iᶠ∋₎ᵐ+}ᶠot), but Jelly has some builtins for parts of the program that have to be spelled out in Brachylog, so this came out shorter.

Explicación

ZŒ!ÆṭṀ
Z            Swap rows and columns
 Œ!          Find all permutations of rows (thus columns of the original)
   Æṭ        {For each permutation}, take the sum of the main diagonal
     Ṁ       Take the maximum

Debe quedar claro que para cualquier solución al problema, podemos permutar las columnas de la matriz original para colocar esa solución en la diagonal principal. Entonces, esta solución simplemente revierte eso, encontrando todas las diagonales principales posibles de permutaciones.

Note that the "permute the columns" operation is done as "transpose, permute the rows" without bothering to transpose back; the rest of the algorithm happens to be symmetrical about the main diagonal, so we don't need to undo the transpose and thus can save a byte.

ais523
fuente
ZŒ!ÆṭṀ saves four bytes. Try it online!
Dennis
Well it looks like Dennis got the last word in :P
Quintec
I wonder if that builtin's ever come up before?
ais523
Not sure, but probably not. I actually suggested ZŒ!ŒD§ṀḢ before remembering that Æṭ was a thing.
Dennis
8

J, 28 bytes

>./@({.+1$:@|:\.|:@}.)@[^:]#

Try it online!

 >./ @  (   {.   +         1 $:@|:\. |:@}.       )       @[^:] #
(max of (1st row + recursive call on each "minor")) or count of arg if 0

Here the recursive call is done by $: which represents the largest anonymous function containing it. We are lucky in J to have the primitive x u\. y, which applies u to successive "outfixes" of y obtained by suppressing successive infixes of length x of the items in y; here we want to surpress successive columns to get "minors", so we transpose |: the lower rows (or tail }.) of y, and then recurse on the transpose of their outfixes.

Olius
fuente
2
Hi and welcome to PPCG! I added a Try it online link for your solution, so that others can verify it.
Galen Ivanov
7

Python 3, 94 90 89 84 80 bytes

-4 bytes thanks to xnor (using sets instead of lists)!

f=lambda x,y={-1}:x>[]and max(e+f(x[1:],y|{i})for(i,e)in enumerate(x[0])if{i}-y)

Try it online!

ბიმო
fuente
Nice method! You can make y a set to shorten the membership check: f=lambda x,y={-1}:x>[]and max(e+f(x[1:],y|{i})for(i,e)in enumerate(x[0])if{i}-y).
xnor
@xnor: That -1 trick is really clever :) Thanks a lot!
ბიმო
7

Husk, 12 11 9 bytes

▲mȯΣ►L∂PT

Try it online!

Thanks to BMO for suggesting a port of ais523's answer and a 2-byte save, which I managed to improve on further, and in turn BMO shaved off 2 more bytes.


Previous solution (14 bytes)

▲moΣz!¹fS=uΠmŀ

Try it online!

I wasn't able to make a test suite because this answer uses the first command line argument command explicitly. But Husk doesn't use STDIN at all so I included all the test cases there, so you can just copy paste in the argument field to check it out. Also note that arrays in Husk may not contain spaces between elements while being inputted.

How it works?

Code breakdown

▲moΣz!¹fS=uΠmŀ     Full program. Takes a 2D list from CLA 1 and outputs to STDOUT.
            mŀ     Length range of each list. 
           Π       Cartesian product.
       fS=u        Discard those combinations which have at least 1 non-unique element.
 mo                Map over the combinations with the following predicate:
    z!¹            Zip the 2D list input with the current combination and index accordingly.
   Σ               Sum the resulting elements.
▲                  Finally, pick the maximum.

Example

Let's pick an example:

(142561)

One must pick exactly one index from each such that no two indices correspond. So, we generate the length ranges of the rows and only keep those without duplicates, yielding the following combinations (each combination is a column instead of a row to save space):

(121323213132)

Then, the program indexes in the input lists with each element of the combination, returning:

(141242651516)

Summing all those results (here, each column, for the aforementioned reason), one obtains all possible valid sums according to the criteria, in this case 9.

Mr. Xcoder
fuente
5

JavaScript (ES6),  74  71 bytes

Thanks to @tsh for identifying 2 useless bytes that were used to fix a bug
Saved 3 bytes thanks to @tsh

f=([a,...r],k,i=1)=>a?Math.max(...a.map(n=>k&(i+=i)?-1/0:n+f(r,k|i))):0

Try it online!

Arnauld
fuente
@Shaggy but it is impossible to compose 0 from input array, -1+(-1) is -2 and it is correct answer.
val says Reinstate Monica
1
f=([a,...r],k,i=1)=>a?Math.max(...a.map(c=>k&(i+=i)?-1/0:c+f(r,k|i))):0 It's strange, but Math.max saves bytes...
tsh
4

Jelly, 13 12 bytes

ẈŒpQƑƇị"€¹§Ṁ

Try it online!

Alternate version, 11 bytes

ZLœ!Lị"€¹§Ṁ

This uses the newly added œ! built-in, which generates all permutations of a given length.

Try it online!

How it works

ẈŒpQƑƇị"€¹§Ṁ  Main link. Argument: M (matrix)

Ẉ             Widths; compute the length of each row.
              For an n×m matrix, this yields an array m copies of n.
 Œp           Cartesian product; promote each n to [1, ..., n], then form all arrays
              that pick one k out of all m copies of [1, ..., n].
   QƑƇ        Comb by fixed unique; keep only arrays that do not change by
              deduplicating their entries.
         ¹    Identity; yield M.
      ị"€     For each of the arrays of unique elements, use its m entries to index
              into the m rows of M.
          §   Take the sums of all resulting vectors.
           Ṁ  Take the maximum.
Dennis
fuente
Ah... I almost posted this same answer with XLṗL instead of J€Œp.
Erik the Outgolfer
4

Haskell, 65 bytes

f(u:v)=maximum[e+f(take i<>drop(i+1)<$>v)|(i,e)<-zip[0..]u]
f _=0

Try it online!

Explanation & Ungolfed

The function take i<>drop(i+1) takes a list and removes the element at position i.

The function f gets each possible element e at position i, removes the elements at position i from the remaining elements and adds e to the recursively computed optimum:

f(u:v)=maximum[e+f(removeElementAt i<$>v)|(i,e)<-zip[0..]u]

And the base case for the empty list is just 0:

f _=0
ბიმო
fuente
2

Brachylog, 18 bytes

{hl⟦kp;?z₀∋₍ᵐ+}ᶠot

Try it online!

Explanation

                ot      The output is the biggest result of…
{             }ᶠ        …finding all outputs to the following predicate:
 hl⟦k                     Construct the range [0, …, n-1]
     p                    Take a permutation of that range
      ;?z₀                Zip that permutation with the Input, stopping when all elements of
                            the input are used (important because the range is possibly
                            bigger than the length of the input)
          ∋₍ᵐ             In each element of the zip, take the head'th element of the tail
             +            Sum the result
Fatalize
fuente
2

Perl 6, 50 49 bytes

{max map *.map({.[$++]}).sum,permutations [Z] $_}

Try it online!

Decently short, even despite the long permutations call. This is an anonymous code block that takes a list of lists and returns a number.

Explanation:

{                                               } # Anonymous code block
 max                                              # Finds the maximum
                             permutations         # Of all permutations
                                          [Z] $_  # Of the transposed input
     map                                          # When mapped to
                        .sum # The sum of
         *.map({.[$++]})     # The diagonal of the matrix
Jo King
fuente
2

K (oK), 40, 32, 28, 19 bytes

-13 bytes thanks to ngn!

{|/+/(prm'x)@''!#x}

Try it online!

Initial solution:

{|/+/'x./:/:(*t),'/:t:{x~?x}#+!(#x)##*x}

Try it online!

Note: Doesn't work for the first test case [[1]]

Explanation:

{ } - function with argument x

                                   #     - creata a list
                               (#x)      - with length number of rows of x
                                    #*x  - of the length of the first row
                              !          - odometer (ranged permutations)
                             +           - transpose
                            #            - filter out the rows
                      {x~?x}             - that have duplicates
                    t:                   - save it to t 
                ,'/:                     - pair up each number in each row with
            (*t)                         - a number from the first row
      x./:/:                             - index x with each of the above
   +/'                                   - find the sum of each row
 |/                                      - reduce by max
Galen Ivanov
fuente
1
hint: prm can be applied directly to a list to generate its permutations
ngn
@ngn Thanks! I wanted to use the main diagonal with =, but the result was longer. Is there flatten in oK?
Galen Ivanov
flatten in what sense?
ngn
@ngn (1 2 3; 4 5 6; 7 8 9) -> (1 2 3 4 5 6 7 8 9)
Galen Ivanov
1
that's just ,/ or if you want it to go into deeper structures: ,//
ngn
2

Haskell, 65 bytes

([]%)
p%(h:t)=maximum[x+(i:p)%t|(i,x)<-zip[0..]h,all(/=i)p]
p%_=0

Try it online!


71 bytes

f m=maximum[sum b|(a,b)<-unzip<$>mapM(zip[0..])m,[x|x<-a,y<-a,x==y]==a]

Try it online!

The [x|x<-a,y<-a,x==y]==a checks that the elements of a are distinct. This uses up a surprising number of characters, but I didn't see a shorter way.

xnor
fuente
1

Pyth, 15 12 bytes

[email protected]

Try it online here.

[email protected]   Implicit: Q=eval(input())
                Trailing Q inferred
          lhQ   Length of first element of Q
        .p      Generate all permutaions of 0 to the above
  m             Map the elements of the above, as d, using:
    @VQd          Vectorised index into Q using d
                    For i in [0-length(Q)), yield Q[i][d[i]]
   s              Take the sum of the above
 S              Sort the result of the map
e               Take the last element of the above, implicit print

Edit: saved 3 bytes courtesy of issacg

Sok
fuente
1
.PUlhQl can be replaced by .plh. V implicitly ignores any extra entries.
isaacg
1

05AB1E, 18 13 bytes

нgLœε‚øε`è]OZ

I have the feeling it's overly long, but I'm not sure how to do vectorized indexing byte-efficiently in 05AB1E.. And I was indeed right that it was too long.. -5 bytes thanks to @Emigna.

Try it online or verify all test cases.

Explanation:

н                # Take the first inner list (of the implicit input list of lists)
 g               # Pop and take its length
  L              # Create a list in the range [1, inner-length]
   œ             # Create each possible permutation of this range-list
    ε            # Map each permutation to:
                #  Pair it with the (implicit) input
      ø          #  Transpose; swap rows/columns
       ε         #  Map each to:
        `        #   Push both to the stack
         è       #   Index the permutation-nr into the inner list of the input
    ]            # Close both maps
     O           # Take the sum of each inner list
      à          # Pop and push the maximum (and output implicitly)

Example run:

  • Input: [[1,4,2],[5,6,1]]
  • After step 1 (нgL): [1,2,3]
  • After step 2 (œ): [[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
  • After step 3 (ε‚): [[[[1,4,2],[5,6,1]],[1,2,3]],[[[1,4,2],[5,6,1]],[1,3,2]],[[[1,4,2],[5,6,1]],[2,1,3]],[[[1,4,2],[5,6,1]],[2,3,1]],[[[1,4,2],[5,6,1]],[3,1,2]],[[[1,4,2],[5,6,1]],[3,2,1]]]
  • After step 4 (ø): [[[[1,4,2],1],[[5,6,1],2]],[[[1,4,2],1],[[5,6,1],3]],[[[1,4,2],2],[[5,6,1],1]],[[[1,4,2],2],[[5,6,1],3]],[[[1,4,2],3],[[5,6,1],1]],[[[1,4,2],3],[[5,6,1],2]]]
  • After step 5 (ε`è]): [[4,1],[4,5],[2,6],[2,5],[1,6],[1,1]] (NOTE: 05AB1E is 0-indexed (with automatic wraparound), so indexing 3 into [5,6,1] results in 5.)
  • After step 6 (O): [5,9,8,7,7,2]
  • Output / after step 7 (à): 9
Kevin Cruijssen
fuente
1
I had нgLœε‚øεè]OZ` for 13.
Emigna
@Emigna Thanks! It's surprisingly similar to what I had I see, except that I added a bunch of crap that was unnecessary. ;p
Kevin Cruijssen
1

Haskell, 84 bytes

import Data.List
h l=maximum[sum$snd<$>r|r<-mapM id$zip[1..]<$>l,(==)=<<nub$fst<$>r]

Try it online!

nimi
fuente
0

Ruby, 74 72 69 bytes

->a{[*0...a[0].size].permutation.map{|x|a.zip(x).sum{|y,z|y[z]}}.max}

Try it online!

Kirill L.
fuente