Encontre uma matriz que se ajuste a um conjunto de somas


17

Considere uma matriz Ade comprimento n. A matriz contém apenas números inteiros positivos. Por exemplo A = (1,1,2,2). Vamos definir f(A)como o conjunto de somas de todos os sub-arranjos contíguos não vazios de A. Nesse caso f(A) = {1,2,3,4,5,6}. As etapas a f(A) serem produzidas são as seguintes:

Os sub-arranjos de Asão (1), (1), (2), (2), (1,1), (1,2), (2,2), (1,1,2), (1,2,2), (1,1,2,2). Suas respectivas somas são 1,1,2,2,2,3,4,4,5,6. O conjunto que você obtém dessa lista é, portanto {1,2,3,4,5,6}.

Tarefa

Dado um conjunto de somas Sfornecidas em ordem classificada, contendo apenas números inteiros positivos e um comprimento de matriz n, sua tarefa é gerar pelo menos uma matriz Xcomo essa f(X) = S.

Por exemplo, se S = {1,2,3,5,6}e, em n = 3seguida, uma saída válida é X = (1,2,3).

Se não houver essa matriz, Xseu código deve gerar qualquer valor constante.

Exemplos

Entrada n=4, S = (1, 3, 4, 5, 6, 8, 9, 10, 13):, saída possível:X = (3, 5, 1, 4)

Entrada n=6, S = (2, 3, 4, 5, 7, 8, 9, 10, 12, 14, 17, 22):, saída possível:X = (5, 3, 2, 2, 5, 5)

Entrada n=6, S = (2, 4, 6, 8, 10, 12, 16):, saída possível:X = (4, 2, 2, 2, 2, 4)

Entrada n=6, S = (1, 2, 3, 4, 6, 7, 8, 10, 14):, saída possível:X = (4, 2, 1, 1, 2, 4)

Entrada: n=10, S = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 15, 16, 17, 18, 19, 20, 23, 24, 25), possível saída: X = (1, 1, 3, 1, 2, 1, 2, 5, 4, 5).

Entrada: n=15, S = (1, 2, 3, 4, 6, 7, 8, 9, 10, 11, 13, 14, 15, 16, 17, 18, 20, 21, 22, 23, 24, 25, 26, 27, 28, 30, 31), possível saída: X = (1, 2, 1, 3, 3, 1, 3, 3, 1, 3, 3, 1, 2, 1, 3).

Formato de entrada e saída

Seu código pode receber e fornecer resultados em qualquer formato de leitura facilmente humano que você achar conveniente. No entanto, mostre a saída do teste nos exemplos da pergunta.

Tempo de execução

Você deve poder executar o código até a conclusão para todos os exemplos na pergunta. Ele deve, em princípio, ser correto para naté 15, mas você não precisa provar que seria rápido o suficiente para todas as entradas.


Comentários não são para discussão prolongada; esta conversa foi movida para o bate-papo .
Dennis

Provavelmente deve ter um caso de teste com um número de 2 dígitos.
Magic Octopus Urn

Respostas:


6

Casca , 20 bytes

ḟȯ⁰¦ṁ∫ṫ!¡Sof~Λ€∫×:¹g

Experimente online!

Retorna uma solução ou uma lista vazia, se não existir. O último caso de teste ( n=15) termina em 3,8 segundos no TIO.

Explicação

O programa tem duas partes. Na primeira parte ( ¡e à direita), construímos uma lista infinita cujo kth é uma lista que contém todas as klistas de comprimento cujas somas de fatia estão S. Fazemos isso de forma indutiva, começando pelas fatias de 1 elemento de S, e em cada etapa precedendo cada elemento de Scada lista e mantendo aqueles cujas somas de prefixo estão S. Na segunda parte ( !e à esquerda), pegamos o nth elemento da lista, que contém nlistas de comprimento . Destes, selecionamos o primeiro cujas somas de fatia realmente contêm todos os elementos de S.

No código, vamos primeiro substituir oe ȯ(que compõem duas e três funções em uma) por parênteses para maior clareza.

¡S(f~Λ€∫)×:¹g  First part. Input is a list, say S=[1,2,3]
            g  Group equal adjacent elements: [[1],[2],[3]]
¡              Iterate function:
                Argument is a list of lists, say [[1,1],[1,2],[2,1]]
         ×      Mix (combine two lists in all possible ways)
          :     by prepending
           ¹    with the list S: [[1,1,1],[1,1,2],[2,1,1],[1,2,1],[2,1,2],[3,1,1],[2,2,1],[3,1,2],[3,2,1]]
   f            Filter by condition:
        ∫        Cumulative sums: [[1,2,3],[1,2,4],[2,3,4],[1,3,4],[2,3,5],[3,4,5],[2,4,5],[3,4,6],[3,5,6]]
     ~Λ          All of the numbers
 S     €         are elements of S: [[1,1,1]]
                 Only this list remains, since the other cumulative sums contain numbers not from S.
               Result of iteration: [[[1],[2],[3]],[[1,1],[1,2],[2,1]],[[1,1,1]],[],[],[]...

ḟ(⁰¦ṁ∫ṫ)!      Second part. Implicit input, say n=2.
        !      Take nth element of above list: [[1,1],[1,2],[2,1]]
ḟ              Find first element that satisfies this:
                Argument is a list, say [1,2]
      ṫ         Tails: [[1,2],[2]]
    ṁ           Map and concatenate
     ∫          cumulative sums: [1,3,2]
 ȯ ¦            Does it contain all elements of
  ⁰             S? Yes.
               Result is [1,2], print implicitly.

Existem algumas partes que precisam de mais explicações. Neste programa, os sobrescritos se ⁰¹referem ao primeiro argumento S. No entanto, se αfor uma função, α¹significa "aplicar αa S", enquanto ⁰αsignifica "conectar Sao segundo argumento de α". A função ¦verifica se o primeiro argumento contém todos os elementos do segundo (contando multiplicidades), assim Sdeve ser o segundo argumento.

Na primeira parte, a função que ¡usa pode ser interpretada como S(f~Λ€∫)(×:)¹. O combinador Sse comporta como Sαβγ -> (αγ)(βγ), o que significa que podemos simplificá-lo (f~Λ€∫¹)(×:¹). A segunda parte ,, ×:¹é "misturar com Sanexando" e seu resultado é passado para a primeira parte. A primeira parte f~Λ€∫¹funciona assim. A função ffiltra uma lista por uma condição, que neste caso é ~Λ€∫¹. Ele recebe uma lista de listas L, então temos ~Λ€∫¹L. O combinador ~se comporta como ~αβγδε -> α(βδ)(γε): o primeiro argumento é passado para β, o segundo para γe os resultados são combinados com α. Isso significa que nós temos Λ(€¹)(∫L). A última parte ∫Lé apenas a soma acumulada de L,€¹é uma função que verifica a associação Se Λaceita uma condição (aqui €¹) e uma lista (aqui ∫L) e verifica se todos os elementos a satisfazem. Simplificando, filtramos os resultados da mistura, independentemente de suas somas cumulativas estarem incluídas S.


Estou ansioso pela explicação!
Anush

1
@ Anush Adicionei um detalhamento de código.
Zgarb

Eu realmente gosto desta solução. É meio bonito.
Anush

6

Ruby , 135 bytes

->a,n{r=w=1;r+=1until w=(s=a[0,r]).product(*[s]*~-n).find{|x|x.sum==a.max&&a==[]|(1..n).flat_map{|r|x.each_cons(r).map(&:sum)}.sort};w}

Experimente online!

Use uma pesquisa pela primeira vez. n = 10 funciona no TIO, n = 15 leva mais de um minuto, mas funciona na minha máquina.

Ruby , 147 bytes

->a,n{r=w=1;r+=1until w=([a[-1]-a[-2]]).product(*[s=a[0,r]]*~-n).find{|x|x.sum==a.max&&a==[]|(1..n).flat_map{|r|x.each_cons(r).map(&:sum)}.sort};w}

Experimente online!

Versão otimizada, funciona no TIO por n = 15 (~ 20 s)

Na verdade, este é o começo de uma abordagem de força não bruta. Espero que alguém trabalhe nisso e encontre uma solução completa.

Primeiras idéias:

  • A soma da matriz de saída é o último elemento (máximo) da matriz de entrada.
  • A soma da matriz de saída menos o primeiro (ou o último) elemento, é o segundo último elemento da matriz de entrada.
  • Se uma matriz é uma solução, a matriz reversa também é uma solução, para que possamos assumir que o primeiro elemento seja a diferença entre os dois últimos elementos da matriz de entrada.
  • O segundo elemento pode ser a diferença entre o segundo e o terceiro ou o segundo e o quarto último elemento da matriz de entrada.

O que nos leva à próxima otimização:

Ruby , 175 bytes

->a,n{r=w=1;r+=1until w=([a[-1]-a[-2]]).product([a[-2]-a[-3],a[-2]-a[-4]],*[s=a[0,r]]*(n-2)).find{|x|x.sum==a.max&&a==[]|(1..n).flat_map{|r|x.each_cons(r).map(&:sum)}.sort};w}

Experimente online!

~ 8,5 segundos no TIO. Não é ruim...

... e assim por diante (a ser implementado)


Isso parece muito bom!
Anush 18/10

Estou empolgado com seus novos algoritmos de força não bruta. Se você quiser mais exemplos para testar, posso adicioná-los a uma nova seção da pergunta.
Anush 18/10

2
@ Anush Na verdade, ainda é a força bruta (tempo exponencial), mas com alguma otimização (fator polinomial).
user202729

Para mim, você esquece que o primeiro elemento (o elemento mais pequeno) está sempre em solução: então temos 1 e o último (a soma de todos); e você diz o penúltimo, mas isso para mim não é claro ... possível lá é uma maneira de encontrar todos os outros desta forma ...
RosLuP

5

Haskell, 117 111 bytes

6 bytes salvos graças ao @nimi!

f r i n s|n<1=[r|r==[]]|1<2=[y:z|y<-s,t<-[y:map(y+)i],all(`elem`s)t,z<-f[a|a<-r,all(a/=)t]t(n-1)s]
n&s=f s[]n s

Experimente online!

frSins

Quando né zero (jogado com golfe n<1) a lista deve estar pronta, portanto, verificamos se todos os valores foram vistos. Caso contrário, retornamos uma lista vazia para indicar nenhuma solução; caso contrário, retornamos uma lista singleton contendo uma lista vazia, na qual os elementos escolhidos serão anexados. Este caso também poderia ter sido tratado com as equações adicionais

f [] _ 0 _=[[]]
f _ _ 0 _=[]

Se nnão for zero, retornamos

[y:z|y<-s,t<-[y:map(y+)i],all(`elem`s)t,z<-f[a|a<-r,all(a/=)t]t(n-1)s]
 ^1^ ^2^^ ^......3......^ ^.....4.....^ ^.............5.............^

Esta é a lista de (1) listas de onde vem o primeiro elemento (2) se o restante (5) da chamada recursiva, sob a condição (4) em que todas as novas somas estão s. As novas somas são computadas em (3) - observe que té extraído de uma lista de singleton, um truque feio para o golfe, como seria o idiomático Haskell let t=y:map(y+)i. A chamada recursiva (5) recebe como novo rconjunto o antigo, sem os elementos que aparecem entre as novas somas t.

A função principal &chama a função auxiliar dizendo que ainda temos que ver todos os valores ( r=s) e que ainda não há somas ( i=[]).

Por mais sete bytes, podemos restringir a computação para fornecer apenas o primeiro resultado (se houver), que é muito mais rápido e lida com todos os casos de teste em menos de 2 segundos.

Experimente online! (este é o primeiro resultado, apenas variação da versão antiga)


1
Isso é incrivelmente rápido. Se você pudesse explicar o algoritmo, isso seria ótimo.
Anush 19/10


Estou pensando em apresentar uma versão de código mais rápida desse problema. Você acha que pode haver uma solução de tempo polivalente?
Anush

@nimi Obrigado! Ah, o bom e velho map, eu só tentei <$>, mas que parens extras necessários ... @Anush Eu não tenho idéia de uma solução em tempo polinomial
Christian Sievers

3

Limpo , 177 bytes

import StdEnv,Data.List
$s n=find(\a=sort(nub[sum t\\i<-inits a,t<-tails i|t>[]])==s)(?{#u\\u<-s|u<=(last s)-n}(last s)n)
?e s n|n>1=[[h:t]\\h<-:e|h<=s-n,t<- ?e(s-h)(n-1)]=[[s]]

Experimente online!

Leva cerca de 40 segundos na minha máquina para o n=15caso de teste, mas o tempo limite é excedido no TIO.

Limpo , 297 bytes

import StdEnv,Data.List
$s n=find(\a=sort(nub[sum t\\i<-inits a,t<-tails i|t>[]])==s)(~[u\\u<-s|u<=(last s)-n](last s)n(reverse s))
~e s n a|n>4=let u=a!!0-a!!1 in[[u,h:t]\\h<-[a!!1-a!!2,a!!1-a!!3],t<- ?e(s-u-h)(n-2)]= ?e s n
?e s n|n>1=[[h:t]\\h<-e,t<- ?(takeWhile((>=)(s-n-h))e)(s-h)(n-1)]=[[s]]

Experimente online!

Este inclui algumas otimizações feitas pelo GB , bem como algumas próprias. Eu acho que alguns deles podem ser mais genéricos, então adicionarei uma explicação assim que estiver pronto.

Demora cerca de 10 segundos na minha máquina, 40 segundos no TIO.


Você poderia explicar as otimizações que usou por favor? Estou muito interessado.
Anush

1
@ Anush Vou editar a resposta com eles e @mentionvocê amanhã, quando chegarem, infelizmente não temos tempo hoje.
Οurous

3

Python 3 , 177 bytes

from itertools import*
s,n=eval(input())
for[*t]in combinations(s[:-2],n-2):
  a=[*map(int.__sub__,t+s[-2:],[0,*t,s[-2]])];
  {sum(a[p//n:p%n+1])for p in range(n*n)}^{0,*s}or-print(a)

Experimente online!

(algumas novas linhas / espaços foram adicionados para evitar que os leitores precisem rolar o código)

Uma porta direta da minha resposta Jelly (com algumas modificações, consulte a seção "observação" abaixo)

Resultado da execução local:

[user202729@archlinux golf]$ printf '%s' "from itertools import*
s,n=eval(input())
for[*t]in combinations(s[:-2],n-2):a=[*map(int.__sub__,t+s[-2:],[0,*t,s[-2]])];{sum(a[p//n:p%n+1])for p in range(n*n)}^{0,*s}or-print(a)" > a.py
[user202729@archlinux golf]$ wc -c a.py
177 a.py
[user202729@archlinux golf]$ time python a.py<<<'([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 15, 16, 17, 18, 19, 20, 23, 24, 25], 10)' 2>/dev/null
[1, 4, 1, 1, 1, 1, 1, 7, 7, 1]

real    0m3.125s
user    0m3.119s
sys     0m0.004s
[user202729@archlinux golf]$ time python a.py<<<'([1, 2, 3, 4, 6, 7, 8, 9, 10, 11, 13, 14, 15, 16, 17, 18, 20, 21, 22, 23, 24, 25, 26, 27, 28, 30, 31], 15)' 2>/dev/null
[3, 1, 2, 1, 3, 3, 1, 3, 3, 1, 3, 3, 1, 2, 1]

real    11m36.093s
user    11m33.941s
sys     0m0.387s
[user202729@archlinux golf]$ 

Ouvi dizer que itertoolsé detalhado, mas minha melhor combinationsimplementação é ainda mais detalhada:

c=lambda s,n,p:s and c(s[1:],n-1,p+s[:1])+c(s[1:],n,p)or[]if n else[p]

Nota .

  • O uso da divisão / módulo a[p//n:p%n+1]leva cerca de duas vezes mais, mas economiza alguns bytes.
  • Isso é um pouco diferente da resposta Jelly - a resposta Jelly itera para trás.
  • Graças ao combinationsretorno de um iterador, isso facilita a memória.

2

Geléia , 35 bytes

Ẇ§QṢ⁼³
;³ṫ-¤0;I
ṖṖœcƓ_2¤¹Ṫ©ÇѬƲ¿ṛ®Ç

Experimente online!

Executar localmente: (n = 15 leva mais de 1 GB de RAM)

aaa@DESKTOP-F0NL48D MINGW64 ~/jellylanguage (master)
$ time python scripts/jelly fu z '[1,2,3,4,5,6,7,8,9,10,11,12,14,15,16,17,18,19,20,23,24,25]'<<<10
[8, 6, 2, 1, 1, 1, 1, 3, 1, 1]
real    0m1.177s
user    0m0.000s
sys     0m0.015s

aaa@DESKTOP-F0NL48D MINGW64 ~/jellylanguage (master)
$ time python scripts/jelly fu z '[1, 2, 3, 4, 6, 7, 8, 9, 10, 11, 13, 14, 15, 16, 17, 18, 20, 21, 22, 23, 24, 25, 2
6, 27, 28, 30, 31]'<<<15
[3, 1, 2, 1, 3, 3, 1, 3, 3, 1, 3, 3, 1, 2, 1]
real    12m24.488s
user    0m0.000s
sys     0m0.015s

(na verdade, eu executei a versão codificada em UTF8, que leva mais de 35 bytes, mas o resultado é o mesmo)

Esta solução usa curto-circuito para reduzir o tempo de execução.

(|S|2n2)×(n36+n2logn2)(262152)×(1536+152log152)5.79×109

Explicação

Observamos que as somas de todos os prefixos não vazios estão presentes na entrada e estão aumentando estritamente. Também podemos assumir que o elemento maior e o segundo maior é uma soma de prefixo.

n2|S|2(|S|2n2)n2n36


Não testado (mas deve ter desempenho idêntico)

Gelatina , 32 bytes

Ṫ©ÑẆ§QṢ⁻³
;³ṫ-¤ŻI
ṖṖœcƓ_2¤¹Ñ¿ṛ®Ç

Experimente online!


Versão mais ineficiente (sem curto-circuito):

Gelatina , 27 bytes

Ẇ§QṢ⁼³
ṖṖœcƓ_2¤µ;³ṫ-¤0;I)ÑƇ

Experimente online!

Para o teste n = 15, são necessários até 2 GB de RAM e não terminam após ~ 37 minutos.


nota : Ẇ§pode ser substituído por ÄÐƤẎ. Pode ser mais eficiente.


1

APL (NARS), caracteres 758, bytes 1516

r←H w;i;k;a;m;j
   r←⊂,w⋄→0×⍳1≥k←↑⍴w⋄a←⍳k⋄j←i←1⋄r←⍬⋄→C
A: m←i⊃w⋄→B×⍳(i≠1)∧j=m⋄r←r,m,¨∇w[a∼i]⋄j←m
B: i+←1
C: →A×⍳i≤k

G←{H⍵[⍋⍵]}

r←a d w;i;j;k;b;c
   k←↑⍴w ⋄b←⍬⋄r←0 ⋄j←¯1
A: i←1⋄j+←1⋄→V×⍳(i+j)>k
B: →A×⍳(i+j)>k⋄c←+/w[i..(i+j)]⋄→0×⍳∼c∊a⋄→C×⍳c∊b⋄b←b,c
C: i+←1⋄→B
V: →0×⍳∼a⊆b
   r←1

r←a F w;k;j;b;m;i;q;x;y;c;ii;kk;v;l;l1;i1;v1
   w←w[⍋w]⋄r←a⍴w[1]⋄l←↑⍴w⋄k←w[l]⋄m←8⌊a-2⋄b←¯1+(11 1‼m)⋄j←2⋄i←1⋄x←↑⍴b⋄i1←0⋄v1←⍬
I: i1+←1⋄l1←w[l]-w[l-i1]⋄v1←v1,w[1+l-i1]-w[l-i1]⋄→I×⍳(l1=i1)∧l>i1⋄→B
E: r←,¯1⋄→0
F: i←1⋄q←((1+(a-2)-m)⍴0),(m⍴1),0⋄r+←q
A:   i+←1⋄j+←1⋄→E×⍳j>4000
B:   →F×⍳i>x⋄q←((1+(a-2)-m)⍴0),b[i;],0⋄q+←r⋄v←q[1..(a-1)]⋄→A×⍳0>k-y←+/v
   q[a]←k-y⋄→A×⍳l1<q[a]⋄→A×⍳∼q⊆w⋄→A×⍳∼l1∊q⋄→A×⍳∼v1⊆⍦q⋄c←G q∼⍦v1⋄ii←1⋄kk←↑⍴c⋄→D
C:   →Z×⍳w d v1,ii⊃c⋄ii+←1
D:   →C×⍳ii≤kk
   →A
Z: r←v1,ii⊃c

A função G em G x (com a ajuda da função H) encontraria todas as permutações de x. A função d em xdy descobre se a matriz y gera após a matriz de exercícios x retornando um valor booleano. A função F em x F y retornaria a matriz r de comprimento x, de modo que ydr seja verdadeiro (= 1) Um pouco longo como implementação, mas é este que calcula todos os casos em teste menos tempo ... O último caso para n = 15 ele roda 20 segundos apenas ... eu tenho que dizer que isso não encontra muitas soluções, retorne apenas uma solução (finalmente parece que sim) em menos tempo (teste não explorado para entradas diferentes ...) 16 + 39 + 42 + 8 + 11 + 11 + 18 + 24 + 24 + 54 + 11 + 12 + 7 + 45 + 79 + 69 + 12 + 38 + 26 + 72 + 79 + 27 + 15 + 6 + 13 (758)

  6 F (2, 3, 4, 5, 7, 8, 9, 10, 12, 14, 17, 22)
5 3 2 2 5 5 
  6 F (2, 4, 6, 8, 10, 12, 16)
4 2 2 2 2 4 
  6 F (1, 2, 3, 4, 6, 7, 8, 10, 14)
4 2 1 1 2 4 
  10 F (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 15, 16, 17, 18, 19, 20, 23, 24, 25)
1 1 3 1 2 3 5 1 3 5 
  15 F (1, 2, 3, 4, 6, 7, 8, 9, 10, 11, 13, 14, 15, 16, 17, 18, 20, 21, 22, 23, 24, 25, 26, 27, 28, 30, 31)
1 2 1 3 3 1 3 3 1 3 3 1 2 1 3 
  ww←(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 15, 16, 17, 18, 19, 20, 23, 24, 25)
  ww≡dx 1 1 3 1 2 3 5 1 3 5 
1
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.