Trova un array che si adatta a una serie di somme


17

Considera una matrice Adi lunghezza n. La matrice contiene solo numeri interi positivi. Per esempio A = (1,1,2,2). Definiamo f(A)come l'insieme delle somme di tutti i sottocampi contigui non vuoti di A. In questo caso f(A) = {1,2,3,4,5,6}. I passaggi per produrre f(A) sono i seguenti:

I subarrays di Asono (1), (1), (2), (2), (1,1), (1,2), (2,2), (1,1,2), (1,2,2), (1,1,2,2). Le loro rispettive somme sono 1,1,2,2,2,3,4,4,5,6. Il set che ottieni da questo elenco è quindi {1,2,3,4,5,6}.

Compito

Dato un insieme di somme Sdate in ordine ordinato contenente solo numeri interi positivi e una lunghezza di array n, il tuo compito è quello di produrre almeno un array in Xmodo tale f(X) = S.

Ad esempio, se S = {1,2,3,5,6}e n = 3quindi un output valido è X = (1,2,3).

Se non esiste tale array, Xil codice dovrebbe generare un valore costante.

Esempi

Input:, n=4, S = (1, 3, 4, 5, 6, 8, 9, 10, 13)possibile output:X = (3, 5, 1, 4)

Input:, n=6, S = (2, 3, 4, 5, 7, 8, 9, 10, 12, 14, 17, 22)possibile output:X = (5, 3, 2, 2, 5, 5)

Input:, n=6, S = (2, 4, 6, 8, 10, 12, 16)possibile output:X = (4, 2, 2, 2, 2, 4)

Input:, n=6, S = (1, 2, 3, 4, 6, 7, 8, 10, 14)possibile output:X = (4, 2, 1, 1, 2, 4)

Ingresso: 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), possibile uscita: X = (1, 1, 3, 1, 2, 1, 2, 5, 4, 5).

Ingresso: 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), possibile uscita: X = (1, 2, 1, 3, 3, 1, 3, 3, 1, 3, 3, 1, 2, 1, 3).

Formato di input e output

Il tuo codice può accettare input e fornire output in qualsiasi formato di lettura facilmente comprensibile per te. Tuttavia, si prega di mostrare l'output del test sugli esempi nella domanda.

Tempo di esecuzione

Devi essere in grado di eseguire il codice fino al completamento per tutti gli esempi nella domanda. In linea di principio dovrebbe essere corretto per un nmassimo di, 15ma non è necessario dimostrare che sarebbe abbastanza veloce per tutti gli input.


I commenti non sono per una discussione estesa; questa conversazione è stata spostata in chat .
Dennis,

Probabilmente dovrebbe avere un caso di test con un numero di 2 cifre.
Magic Octopus Urn

Risposte:


6

Buccia , 20 byte

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

Provalo online!

Restituisce una soluzione o un elenco vuoto se non esiste. L'ultimo test case ( n=15) termina in 3,8 secondi su TIO.

Spiegazione

Il programma ha due parti. Nella prima parte ( ¡e alla sua destra), costruiamo un elenco infinito il cui kelemento th è un elenco che contiene tutti gli kelenchi di lunghezza le cui somme di sezione sono presenti S. Lo facciamo induttivamente, partendo dalle sezioni di 1 elemento di S, e ad ogni passo anteponendo ciascun elemento Sa ciascuna lista e mantenendo quelli i cui prefissi sono presenti S. Nella seconda parte ( !e alla sua sinistra) prendiamo il nth elemento della lista, che contiene nliste di lunghezze . Di questi, selezioniamo il primo le cui somme di slice contengono effettivamente ogni elemento di S.

Nel codice, per prima cosa sostituiamo oe ȯ(che compongono due e tre funzioni in una) tra parentesi per chiarezza.

¡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.

Ci sono alcune parti che richiedono ulteriori spiegazioni. In questo programma, ⁰¹entrambi gli apici fanno riferimento al primo argomento S. Tuttavia, se αè una funzione, allora α¹significa "applica αa S", mentre ⁰αsignifica "plug Sal secondo argomento di α". La funzione ¦controlla se il suo primo argomento contiene tutti gli elementi del secondo (conteggio delle molteplicità), quindi Sdovrebbe essere il suo secondo argomento.

Nella prima parte, la funzione che ¡utilizza può essere interpretata come S(f~Λ€∫)(×:)¹. Il combinatore Ssi comporta come Sαβγ -> (αγ)(βγ), il che significa che possiamo semplificarlo (f~Λ€∫¹)(×:¹). La seconda parte, ×:¹"si mescola con il Sprepending", e il suo risultato viene passato alla prima parte. La prima parte f~Λ€∫¹, funziona così. La funzione ffiltra un elenco in base a una condizione, che in questo caso è ~Λ€∫¹. Riceve un elenco di elenchi L, quindi abbiamo ~Λ€∫¹L. Il combinatore ~si comporta come ~αβγδε -> α(βδ)(γε): il primo argomento viene passato β, il secondo a γe i risultati vengono combinati con α. Questo significa che abbiamo Λ(€¹)(∫L). L'ultima parte ∫Lè solo la somma cumulativa di L,€¹è una funzione che controlla l'appartenenza Se Λaccetta una condizione (qui €¹) e un elenco (qui ∫L) e verifica che tutti gli elementi la soddisfino. In parole povere, filtriamo i risultati del mixaggio in base alla somma totale delle somme S.


Non vedo l'ora di dare una spiegazione!
Anush,

1
@Anush ho aggiunto una suddivisione del codice.
Zgarb,

Mi piace molto questa soluzione. È abbastanza bello.
Anush,

6

Rubino , 135 byte

->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}

Provalo online!

Usa una prima ricerca. n = 10 funziona su TIO, n = 15 richiede più di un minuto, ma funziona sulla mia macchina.

Rubino , 147 byte

->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}

Provalo online!

Versione ottimizzata, funziona su TIO per n = 15 (~ 20 sec)

In realtà, questo è l'inizio di un approccio senza forza bruta. Spero che qualcuno ci lavori e trovi una soluzione completa.

Prime idee:

  • La somma dell'array di output è l'ultimo elemento (max) dell'array di input.
  • La somma dell'array di output meno il primo (o l'ultimo) elemento, è il secondo ultimo elemento dell'array di input.
  • Se un array è una soluzione, anche l'array inverso è una soluzione, quindi possiamo supporre che il primo elemento sia la differenza tra gli ultimi 2 elementi dell'array di input.
  • Il secondo elemento può essere la differenza tra il secondo e il terzo o il secondo e il quarto ultimo elemento dell'array di input.

Il che ci porta alla prossima ottimizzazione:

Rubino , 175 byte

->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}

Provalo online!

~ 8,5 secondi su TIO. Non male...

... e così via (da attuare)


Sembra molto bello!
Anush,

Sono entusiasta dei tuoi nuovi algoritmi di forza non bruta. Se desideri ulteriori esempi su cui testare, posso aggiungerli a una nuova sezione della domanda.
Anush,

2
@Anush In realtà è ancora forza bruta (tempo esponenziale), ma con qualche ottimizzazione (fattore polinomiale).
user202729

Per me dimentichi che il primo elemento (l'elemento più piccolo) è sempre in soluzione: quindi abbiamo 1 e l'ultimo (la somma di tutti); e tu dici il secondo ultimo, ma questo per me non è chiaro ... è possibile che ci sia un modo per trovare tutti gli altri in questo modo ...
RosLuP

5

Haskell, 117 111 byte

6 byte salvati grazie a @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

Provalo online!

frSins

Quando nè zero (a golf n<1) l'elenco deve essere pronto, quindi controlliamo se tutti i valori sono stati visti. In caso contrario, restituiamo un elenco vuoto per indicare nessuna soluzione, altrimenti restituiamo un elenco singleton contenente un elenco vuoto, al quale verranno anteposti gli elementi scelti. Questo caso potrebbe anche essere stato gestito con le equazioni aggiuntive

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

Se nnon è zero, torniamo

[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.............^

Questo è l'elenco di (1) elenchi da cui proviene il primo elemento (2) se il resto (5) proviene dalla chiamata ricorsiva, a condizione (4) in cui si trovano tutte le nuove somme s. Le nuove somme sono calcolate in (3) - nota che tè tratta da una lista singleton, un brutto trucco da golf per quello che sarebbe in Haskell idiomatico let t=y:map(y+)i. La chiamata ricorsiva (5) diventa nuova rimpostando quella vecchia senza quegli elementi che compaiono tra le nuove somme t.

La funzione principale &chiama la funzione helper dicendo che dobbiamo ancora vedere tutti i valori ( r=s) e che non ci sono ancora somme ( i=[]).

Per altri sette byte, possiamo limitare il calcolo per dare solo il primo risultato (se presente), che è molto più veloce e gestisce tutti i casi di test in meno di 2 secondi.

Provalo online! (questo è il primo risultato unica variazione della vecchia versione)


1
Questo è incredibilmente veloce. Se potessi spiegare l'algoritmo sarebbe fantastico.
Anush,


Sto pensando di proporre una versione del codice più veloce di questo problema. Pensi che potrebbe esserci una soluzione poli-tempo?
Anush,

@nimi Grazie! Ah, buon vecchio map, ci ho solo provato <$>ma mi servivano parenti extra ... @Anush non ho idea di una soluzione temporale polinomiale
Christian Sievers,

3

Pulito , 177 byte

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]]

Provalo online!

Richiede circa 40 secondi sulla mia macchina per il n=15caso di test, ma scade il tempo su TIO.

Pulito , 297 byte

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]]

Provalo online!

Questo include alcune ottimizzazioni fatte da GB e alcune delle mie. Penso che alcuni di essi possano essere resi più generici, quindi una volta fatto aggiungerò una spiegazione.

Ci vogliono circa 10 secondi sulla mia macchina, 40 secondi su TIO.


Potresti precisare le ottimizzazioni che hai usato per favore? Sono molto interessato.
Anush,

1
@Anush, modificherò la risposta con loro e @mentiontu domani quando saranno attivi, purtroppo non ho tempo oggi.
Οurous

3

Python 3 , 177 byte

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)

Provalo online!

(alcune nuove righe / spazi aggiunti per evitare che i lettori debbano scorrere il codice)

Una porta diretta della mia risposta Jelly (con alcune modifiche, vedere la sezione "note" di seguito)

Risultato della corsa locale:

[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]$ 

Ho sentito che itertoolsè prolisso, ma la mia migliore combinationsimplementazione è ancora più dettagliata:

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 .

  • L'uso di division / modulo in a[p//n:p%n+1]richiede circa 2 volte più a lungo, ma consente di risparmiare alcuni byte.
  • Questo è un po 'diverso dalla risposta di Jelly: la risposta di Jelly scorre al contrario.
  • Grazie alla combinationsrestituzione di un iteratore, questo è più amichevole per la memoria.

2

Gelatina , 35 byte

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

Provalo online!

Esegui localmente: (n = 15 richiede più di 1 GB di 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

(in realtà ho eseguito la versione con codifica UTF8, che richiede più di 35 byte, ma il risultato è lo stesso comunque)

Questa soluzione utilizza il corto circuito per ridurre il tempo di esecuzione.

Senza cortocircuiti, questo codice richiede circa (|S|-2n-2)×(n36+n2logn2) operazioni, che valuta (26-215-2)×(1536+152log152)5.79×109, tuttavia a causa dell'inefficienza di Python e Jelly, ci vuole un'eternità per completare. Grazie al corto circuito, può finire molto prima.

Spiegazione

Notiamo che le somme di tutti i prefissi non vuoti sono presenti nell'input e sono in costante aumento. Possiamo anche supporre che l'elemento più grande e il secondo più grande sia una somma di prefisso.

Pertanto, possiamo considerare tutti i modi di scegliere n-2 elementi distinti dal primo |S|-2 elementi (ci sono (|S|-2n-2)tali elenchi), calcola le differenze consecutive per recuperare gli elementi; quindi controlla se è valido in modo ingenuo (ottieni tutton2subarrays, calcola la somma, unifica. La lunghezza totale dei subarrays è di circan36)


Non testato (ma dovrebbe avere prestazioni identiche)

Gelatina , 32 byte

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

Provalo online!


Versione più inefficiente (senza corto circuito):

Gelatina , 27 byte

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

Provalo online!

Per il test n = 15, ci vogliono fino a 2 GB di RAM e non termina dopo ~ 37 minuti.


nota : Ẇ§può essere sostituito con ÄÐƤẎ. Potrebbe essere più efficiente.


1

APL (NARS), caratteri 758, byte 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

La funzione G in G x (con l'aiuto della funzione H) troverebbe tutte le permutazioni di x. La funzione d in xdy trova se l'array y si genera seguendo l'array di esercizio x restituendo un valore booleano. La funzione F in x F y restituirebbe l'array r di lunghezza x, in modo tale che ydr sia vero (= 1) Un po 'lungo come implementazione, ma è questo che calcola tutti i casi in test meno tempo ... L'ultimo caso per n = 15 funziona solo 20 secondi ... devo dire che non trova molte soluzioni, restituisce solo una soluzione (finalmente sembra così) in meno tempo (test non esplorato per diversi input ...) 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
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.