Розділіть список!


10

У цьому виклику вам потрібно розділити список, де розділи мають максимальний розмір, мінімальний розмір та бажаний розмір. Я буду використовувати позначення (min,pref,max) для позначення розмірів у цьому виклику.

Для незнайомих людей з розділенням наступний список розділений на частини 3:
[0..9] -> [[0,1,2],[3,4,5],[6,7,8]]

Якщо у списку ще остачі, вам потрібні розділи , щоб бути як можна ближче до кращого розміром , наскільки це можливо: [0..10], (2,4,5) -> [[0,1,2,3],[4,5,6],[7,8,9]]. Цей розподіл є кращим [[0,1,2,3],[4,5,6,7],[8,9]], хоча останній має більшу бажану довжину. Формально нам потрібно мінімізувати суму (partitionLength-preferredSize)^2для кожного розділу.

Порядок довжин розділів не має значення: For [0..5], (2,3,3), [[0,1,2],[3,4]]або [[0,1],[2,3,4]]працює. Якщо немає розділу не можливо, повертає порожній масив: [0..7], (4,4,5) -> [].

Ви можете припустити, що 1<=min<=pref<=maxі що переданий вам масив є не порожнім масивом цілих чисел. Масив завжди буде першим аргументом. Ви можете приймати min, max та pref у будь-якому порядку та як кортеж або як окремі аргументи.

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

Тестові приклади:

[1], (1,3,4)         -> [[1]]
[100], (1,2,3)       -> [[100]]
[1,2], (1,1,2)       -> [[1],[2]]
[1,2], (1,2,2)       -> [[1,2]]
[1,2], (1,3,3)       -> [[1,2]]
[1,2,3], (1,2,3)     -> [[1,2],[3]] or [[1,2,3]]
[1,2,3,4], (1,3,4)   -> [[1,2,3,4]]
[1,2,3,4,5], (3,3,4) -> []
[1,2,3,4,5], (2,2,2) -> []
[1,2,3,4,5], (3,3,5) -> [[1,2,3,4,5]]
[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49], (2,6,6) -> [[1,2,3,4,5,6],[7,8,9,10,11,12],[13,14,15,16,17,18],[19,20,21,22,23,24],[25,26,27,28,29],[30,31,32,33,34],[35,36,37,38,39],[40,41,42,43,44],[45,46,47,48,49]]

Це , тому націліться на якомога менше байтів на улюбленій мові!


Позначення, яке ви використовуєте, [a..b]включає aі виключає b, правильно?
Алекс А.

Включно, B ексклюзив.
Натан Меррілл

Зауважте, що ваша інтерпретація a не збігається з розділом із теорії множин ...
agtoever

Але це ефективно еквівалентно целочисленного секціонування.
Натан Меррілл

Що робити, якщо рішення немає?
feersum

Відповіді:


2

Хаскелл, 152

_%0=[]
s%k|(a,b)<-splitAt(div(z s)k)s=a:b%(k-1)
z=length
f s n p x=snd$minimum$(z s*p^2,[]):[(sum[(z x-p)^2|x<-s%k],s%k)|k<-[-div(-z s)x..div(z s)n]]

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

Потім програма працює на всіх можливих обсягах списків у розділі. враховуючи кількість списків у розділі, оцінка визначається однозначно. програма обчислює придатний розділ та його бал.

то він знаходить загальний мінімум і повертає його.

Використання: введення як f [1,2,3,4,5] 1 3 4( fце функція, яка вирішує завдання)

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

_%0=[]
s%k|(a,b)<-splitAt(div(length s)k)s=a:b%(k-1)
f s n p x|l<-length s=(s%)$snd$minimum$(l*p^2,0):[(k*j^2+mod l k*(1-2*j),k)|k<-[1..div l n],k*x>=l,j<-[p-div l k]]

1

CJam, 70

q~:S;_,[0L]a{_S2=e<),S0=>f{[__S1=-_*\]@@-j.+}[esL]a+:e<}j1={/(\e_}/;]p

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

Код знаходить оптимальну послідовність розмірів розділів на основі розміру списку, використовуючи динамічне програмування (через запам’ятовувану рекурсію), після чого йде вперед і розділяє список.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.