Знайдіть масив, який відповідає набору сум


17

Розглянемо масив Aдовжини n. Масив містить лише додатні цілі числа. Наприклад A = (1,1,2,2). Давайте визначимо f(A)як сукупність сум усіх непустих суміжних підмагістралей A. У цьому випадку f(A) = {1,2,3,4,5,6}. Етапи для створення f(A) наступні:

Підматриці Aє (1), (1), (2), (2), (1,1), (1,2), (2,2), (1,1,2), (1,2,2), (1,1,2,2). Їх відповідні суми є 1,1,2,2,2,3,4,4,5,6. Отже, набір, який ви отримуєте з цього списку, є {1,2,3,4,5,6}.

Завдання

Враховуючи набір сум, Sвідведених у відсортованому порядку, що містить лише додатні цілі числа та довжину масиву n, ваше завдання полягає у виведенні принаймні одного масиву Xтакого f(X) = S.

Наприклад, якщо S = {1,2,3,5,6}і n = 3тоді є дійсний вихід X = (1,2,3).

Якщо такого масиву немає, Xваш код повинен виводити будь-яке постійне значення.

Приклади

Вхід:, n=4, S = (1, 3, 4, 5, 6, 8, 9, 10, 13)можливий вихід:X = (3, 5, 1, 4)

Вхід:, n=6, S = (2, 3, 4, 5, 7, 8, 9, 10, 12, 14, 17, 22)можливий вихід:X = (5, 3, 2, 2, 5, 5)

Вхід:, n=6, S = (2, 4, 6, 8, 10, 12, 16)можливий вихід:X = (4, 2, 2, 2, 2, 4)

Вхід:, n=6, S = (1, 2, 3, 4, 6, 7, 8, 10, 14)можливий вихід:X = (4, 2, 1, 1, 2, 4)

Вхідний сигнал: 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), можливо вихід: X = (1, 1, 3, 1, 2, 1, 2, 5, 4, 5).

Вхідний сигнал: 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), можливо вихід: X = (1, 2, 1, 3, 3, 1, 3, 3, 1, 3, 3, 1, 2, 1, 3).

Формат вводу та виводу

Ваш код може приймати дані та давати вихід у будь-якому зручному для вас читанні форматі. Однак, покажіть, будь ласка, результати тестування на прикладах із запитання.

Тривалість роботи

Ви повинні мати можливість запустити код до завершення для всіх прикладів питання. В принципі, це повинно бути правильним nдо, 15але вам не потрібно доводити, що це буде досить швидко для всіх матеріалів.


Коментарі не для розширеного обговорення; ця розмова переміщена до чату .
Денніс

Напевно, має бути тестовий випадок із двозначним номером.
Чарівний восьминога Урна

Відповіді:


6

Лушпиння , 20 байт

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

Спробуйте в Інтернеті!

Повертає одне рішення або порожній список, якщо його не існує. Останній тестовий випадок ( n=15) закінчується за 3,8 секунди на TIO.

Пояснення

Програма складається з двох частин. У першій частині ( ¡і праворуч від неї) ми побудуємо нескінченний список, kелементом якого є список, що містить усі kсписки довжин , суми фрагментів яких знаходяться S. Ми робимо це індуктивно, починаючи з фрагментів 1-го елемента Sта на кожному кроці попередньо додаючи кожен елемент Sдо кожного списку та зберігаючи ті, чиї суми префікса є S. У другій частині ( !і зліва від неї) беремо цей nелемент списку, який містить nсписки довжин . З них ми вибираємо перший, чий зріз суми насправді містить кожен елемент S.

У коді давайте спочатку замінемо oі ȯ(які складають дві та три функції в одну) дужками для наочності.

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

Є деякі частини, які потребують більшого пояснення. У цій програмі і надписи ⁰¹посилаються на перший аргумент S. Однак, якщо αце функція, то α¹означає "застосувати αдо S", тоді як ⁰αозначає "підключити Sдо другого аргументу α". Функція ¦перевіряє, чи містить у своєму першому аргументі всі елементи другого (рахуючи кратності), таким Sповинен бути і другий аргумент.

У першій частині функцію, яку ¡використовують, можна інтерпретувати як S(f~Λ€∫)(×:)¹. Комбінатор Sведе себе так Sαβγ -> (αγ)(βγ), це означає, що ми можемо спростити його (f~Λ€∫¹)(×:¹). Друга частина, ×:¹"змішується з попередньою Sформою", і її результат передається першій частині. Перша частина f~Λ€∫¹, працює так. Функція fфільтрує список за умовою, яка в цьому випадку є ~Λ€∫¹. Він отримує список списків L, так що ми маємо ~Λ€∫¹L. Комбінатор ~веде себе так ~αβγδε -> α(βδ)(γε): перший аргумент передається β, другий - γі результати поєднуються з α. Це означає, що ми маємо Λ(€¹)(∫L). Остання частина ∫L- це лише сукупні суми L,€¹це функція, яка перевіряє членство в S, Λприймає умову (тут €¹) і список (тут ∫L) і перевіряє, чи всі елементи його задовольняють. Простіше кажучи, ми фільтруємо результати перемішування за тим, чи всі їх сукупні суми S.


Я з нетерпінням чекаю пояснення!
Ануш

1
@Anush Я додав розбиття коду.
Згарб

Мені дуже подобається таке рішення. Це щось прекрасне.
Ануш

6

Рубін , 135 байт

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

Спробуйте в Інтернеті!

Використовуйте пошук за шириною. n = 10 працює на TIO, n = 15 займає більше хвилини, але працює на моїй машині.

Рубін , 147 байт

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

Спробуйте в Інтернеті!

Оптимізована версія, працює над TIO протягом n = 15 (~ 20 сек)

Власне, це початок підходу без грубої сили. Я сподіваюся, що хтось попрацює над цим і знайде повне рішення.

Перші ідеї:

  • Сума вихідного масиву є останнім елементом (max) вхідного масиву.
  • Сума вихідного масиву мінус перший (або останній) елемент - другий останній елемент вхідного масиву.
  • Якщо масив є рішенням, то і зворотний масив є рішенням, тому ми можемо вважати, що перший елемент - це різниця між останніми двома елементами вхідного масиву.
  • Другим елементом може бути різниця між другим і третім або другим і четвертим останнім елементом вхідного масиву.

Що підводить нас до наступної оптимізації:

Рубін , 175 байт

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

Спробуйте в Інтернеті!

~ 8,5 секунд на TIO. Непогано...

... і так далі (підлягає впровадженню)


Це виглядає дуже приємно!
Ануш

Я схвильований вашими новими алгоритмами, що не стосуються грубої сили. Якщо ви хочете більше прикладів для тестування, я можу додати їх до нового розділу питання.
Ануш

2
@Anush Насправді це все ще груба сила (експоненційний час), але з деякою оптимізацією (поліноміальний фактор).
користувач202729

Для мене ви забуваєте, що перший елемент (елемент більш маленький) він завжди знаходиться в розв’язку: значить, у нас є 1 і останній (сума всіх); і ви говорите друге останнє, але це для мене не зрозуміло ... можливо, існує спосіб знайти всіх інших таким чином ...
RosLuP

5

Haskell, 117 111 байт

6 байт збережено завдяки @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

Спробуйте в Інтернеті!

frSins

Коли nдорівнює нулю (гольф до n<1), список повинен бути готовим, тому ми перевіряємо, чи всі значення були помічені. Якщо ні, ми повертаємо порожній список, щоб не вказати рішення, інакше повертаємо однотонний список, що містить порожній список, до якого обрані елементи будуть попередньо висунуті. Цей випадок також міг оброблятися додатковими рівняннями

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

Якщо nне дорівнює нулю, повертаємося

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

Це перелік (1) списків, звідки походить перший елемент (2), sа решта (5) - від рекурсивного виклику, за умови (4), що всі нові суми s. Нові суми обчислюються в (3) - зауважте, що tвиведено із списку синглів, некрасивого хакерського гольфу для того, що в ідіоматичному Хаскелі було б let t=y:map(y+)i. Рекурсивний виклик (5) отримує як новий rнабір старого без тих елементів, які з'являються серед нових сум t.

Основна функція &викликає функцію помічника, кажучи, що нам ще належить побачити всі значення ( r=s) і що ще немає сум ( i=[]).

Для ще семи байтів ми можемо обмежити обчислення лише першим результатом (якщо такий є), який набагато швидше і обробляє всі тестові справи менше ніж за 2 секунди.

Спробуйте в Інтернеті! (це перший варіант лише варіації старої версії)


1
Це дивно швидко. Якби ви могли пояснити алгоритм, це було б чудово.
Ануш


Я думаю про створення найшвидшої версії коду цієї проблеми. Як ви думаєте, може бути рішення у часі?
Ануш

@nimi Дякую! Ах, добрий старий map, я лише спробував, <$>але для цього потрібні додаткові парен ... @Anush Я не маю уявлення про рішення поліномічного часу
Крістіан Сіверс

3

Чисто , 177 байт

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

Спробуйте в Інтернеті!

n=15Тест займає близько 40 секунд на моїй машині , але час TIO закінчується.

Чисто , 297 байт

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

Спробуйте в Інтернеті!

Це включає деякі оптимізації, зроблені компанією ГБ , а також деякі мої власні. Я думаю, що деякі з них можна зробити більш загальними, тому я додам пояснення, коли це буде зроблено.

На моїй машині це займає близько 10 секунд, на TIO - 40 секунд.


Не могли б ви прописати оптимізації, якими ви скористалися? Мені дуже цікаво.
Ануш

1
@Anush Я відредагую відповідь з ними, а @mentionти завтра, коли вони будуть, на жаль, не маю часу сьогодні.
Οurous

3

Пітон 3 , 177 байт

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)

Спробуйте в Інтернеті!

(додано нові рядки / пробіли, щоб уникнути необхідності прокручування читачів кодом)

Прямий порт моєї відповіді Jelly (з деякими модифікаціями див. Розділ "Примітка" нижче)

Місцевий результат запуску:

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

Я чув, що itertoolsце багатослівний, але найкраще combinationsвиконання - це ще більш багатослівне:

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]

Примітка .

  • Використання поділу / модуля a[p//n:p%n+1]займає приблизно 2 рази довше, але економить деякі байти.
  • Це трохи відрізняється від відповіді «Желе» - відповідь «Желе» повторює назад.
  • Завдяки combinationsповерненню ітератора це зручніше для пам’яті.

2

Желе , 35 байт

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

Спробуйте в Інтернеті!

Запустити локально: (n = 15 займає більше 1 ГБ оперативної пам’яті)

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

(насправді я запустив кодовану UTF8 версію, яка займає більше 35 байт, але результат все одно такий же)

Це рішення використовує коротке замикання для скорочення часу роботи.

(|S|-2н-2)×(н36+н2журналн2)(26-215-2)×(1536+152журнал152)5.79×109

Пояснення

Зауважимо, що суми всіх непустих префіксів є у вхідних даних, і вони суворо збільшуються. Можна також припустити, що найбільший і другий за величиною елемент - це префіксальна сума.

н-2|S|-2(|S|-2н-2)н2н36


Неперевірений (але має мати однакові показники)

Желе , 32 байти

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

Спробуйте в Інтернеті!


Більш неефективна версія (без короткого замикання):

Желе , 27 байт

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

Спробуйте в Інтернеті!

Для n = 15 тестування потрібно до 2 Гб оперативної пам’яті і не закінчується через ~ 37 хвилин.


Примітка : Ẇ§може бути замінено на ÄÐƤẎ. Це може бути ефективніше.


1

APL (NARS), символи 758, байти 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

Функція G в G x (за допомогою функції H) знайшла б усі перестановки x. Функція d в xdy знаходить, якщо масив y генерується після масиву вправ x, що повертає булеве значення. Функція F in x F y повертає масив r довжиною x, таким, що ydr є істинним (= 1) Трохи довгий як реалізація, але саме ця обчислює всі випадки в тесті менше часу ... Останній випадок для n = 15 він працює лише 20 секунд ... я повинен сказати, що це не знайде багато рішень, поверніть лише одне рішення (нарешті, здається, так) за менший час (не досліджений тест для різних входів ...) 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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.