Мінімальна кількість стрибків


14

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

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

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

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

Вхід:

2 4 2 2 3 4 2 2

Вихід:

6 (3 до кінця і 3 для повернення)

Вхідні дані

1 0

Вихідні дані

-1

Примітка

  • Припустимо, що всі числа послідовності є негативними

РЕДАКТ 1

Рядок "Таким чином, повинно бути зрозуміло, що завжди можна стрибати з останньої позиції". може бути заплутаним, тому я усунув це з питання. Це не вплине на питання.

Критерії виграшу:

Переможцем стане той, хто має найкоротший код.


3
Thus, it should be clear that one can always jump from the last position.- це не 1 0контрприклад?
Даніель Любаров

@ Даніель №. Кількість стрибків буде дорівнює значенню, збереженому в цій позиції. Остання посада - це завжди кандидат, з якого можна стрибати, оскільки ця позиція раніше не використовувалася для стрибків.
Кодування людина

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

1
Який критерій виграшу? Як ви помітили код-гольф , а також виклик коду, це не ясно.
Говард

@breadbox Так. Я згоден, його неоднозначно. Я скоро оновлю це питання.
Кодування людини

Відповіді:


4

APL (Діалог), 116

f←{{⊃,/{2>|≡⍵:⊂⍵⋄⍵}¨⍵}⍣≡1{(⍴⍵)≤y←⊃⍺:⍵⋄⍵[y]=0:0⋄x←⍵⋄x[y]←0⋄∇∘x¨,∘⍺¨y+⍳y⌷⍵},⍵}
{0≡+/⍵:¯1⋄(⌊/+/0=⍵)-+/0=x}↑⊃,/f¨⌽¨f x←⎕

Тестові справи

      2 4 2 2 3 4 2 2
6
      1 0
¯1
      1 1 1 1
¯1
      3 1 2 0 4
3
      1
0

Підхід

Підхід - це жорстокий пошук сили за допомогою рекурсивної функції.

Починаючи з позиції 1, встановіть значення в поточному положенні на 0 і генеруйте масив позицій, до яких можна перейти з поточного положення. Передайте нове положення та модифікований масив собі. Базові випадки, коли значення в поточній позиції дорівнює 0 (не можна стрибати) або доходить до кінця.

Потім для кожного створеного масиву переверніть його та повторіть пошук. Оскільки позиції, що перейшли, встановлені на 0, ми не можемо знову стрибати звідти.

Для тих масивів, які ми дійшли до кінця, знайдіть ті, у яких мінімальна кількість 0. Віднімання з нього числа 0 у початковому масиві дає фактичну кількість виконаних стрибків.


4

Математика, 197 193 чол

Груба сила.

Min[Length/@Select[Join[{1},#,{n},Reverse@#2]&@@@Tuples[Subsets@Range[3,n=Length[i=FromDigits/@StringSplit@InputString[]]]-1,2],{}⋃#==Sort@#∧And@@Thread[i[[#]]≥Abs[#-Rest@#~Append~1]]&]]/.∞->-1 

Дуже вражаюча робота. Це може бути жорстокою силою, але це дуже елегантно.
DavidC

3

Математика 351

[Примітка: Це ще не повністю гольф; Також введення потрібно відрегулювати відповідно до потрібного формату. І правило "двічі стрибати на одній і тій же позиції" потрібно реалізувати. Також є деякі проблеми форматування коду, які потребують вирішення. Але це початок.]

Графік побудований з вузлів, відповідних кожній позиції, тобто кожної вхідної цифри, що представляє стрибок. DirectedEdge[node1, node2]означає, що можна перейти з вузла1 до вузла 2. Найкоротші шляхи знаходять від початку до кінця, а потім від кінця до початку.

f@j_:=
(d={v=FromCharacterCode/@(Range[Length[j]]+96),j}\[Transpose];
w[n_,o_:"+"]:={d[[n,1]],FromCharacterCode/@(ToCharacterCode[d[[n,1]]][[1]]+Range[d[[n,2]]]  
If[o=="+",1,-1])};

y=Graph[Flatten[Thread[DirectedEdge[#1,#2]]&@@@(Join[w[#]&/@Range[8],w[#,3]&/@Range[8]])]];

(Length[Join[FindShortestPath[y,v[[1]],v[[-1]]],FindShortestPath[y,v[[-1]],v[[1]]]]]-2)
/.{0-> -1})

Використання

f[{2,4,2,2,3,4,2,2}]
f[{3,4,0,0,6}]
f[{1,0}]

6
3
-1


Це частково неправильно, оскільки воно не примушує виконувати правило без скачування на число два рази, але це початок, тому я буду підтримувати це. Я не мав уявлення, чи це можливо навіть :)
Doorknob

Ви праві. Я зауважив правило, що не стрибає номер два рази. Завтра я спробую це виправити.
DavidC

3

Пітон 304

Я думаю, що цей новий підхід вирішує (сподіваюся!) Всі питання щодо [2,0] справи та подібного:

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

## Back and forward version

# Changed: now the possible jumps from a given L[i] position  
# are at most until the end of the sequence 
def AvailableJumps(L,i): return range(1,min(L[i]+1,len(L)-i))

# In this version we add a boolean variable bkw to keep track of the
# direction in which the sequence is being traversed
def Jumps(L,i,n,S,bkw):
    # If we reach the end of the sequence...
    # ...append the new solution if going backwards
    if (bkw & (i == len(L)-1)): 
            S.append(n)
    else:
        # ...or start again from 0 with the reversed sequence if going forward
        if (i == len(L)-1):
            Jumps(L[::-1],0,n,S,True)    
        else:
            Laux = list(L)
            # Now we only have to disable one single position each time
            Laux[i] = 0
            for j in AvailableJumps(L,i):
                Jumps(Laux,i+j,n+1,S,bkw)

def MiniJumpBF(L):
    S = []        
    Jumps(L,0,0,S,False)
    return min(S) if (S) else -1

Це версії для гольфу:

def J(L,i,n,S,b):
    if (i == len(L)-1):
        S.append(n) if b else J(L[::-1],0,n,S,True)
    else:
        L2 = list(L)
        L2[i] = 0
        for j in range(1,min(L[i]+1,len(L)-i)):
            J(L2,i+j,n+1,S,b)
def MJ(L):
    S = []        
    J(L,0,0,S,False)
    return min(S) if (S) else -1

І кілька прикладів:

MJ( [2, 4, 2, 2, 3, 4, 2, 2] ) -->  6
MJ( [0, 2, 4, 2, 2, 3, 4, 2, 2] ) -->  -1
MJ( [3, 0, 0, 1, 4] ) -->  3
MJ( [2, 0] ) -->  -1
MJ( [1] ) -->  0
MJ( [10, 0, 0, 0, 0, 0, 10, 0, 0, 0, 10, 0, 0, 0, 0, 0, 10] ) -->  4
MJ( [3, 2, 3, 2, 1] ) -->  5
MJ( [1, 1, 1, 1, 1, 1, 6] ) -->  7
MJ( [7, 1, 1, 1, 1, 1, 1, 7] ) -->  2

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

1
у вас є тони непотрібного пробілу ...
Дверна ручка

3

R - 195

x=scan(nl=1)
L=length
n=L(x)
I=1:(2*n-1)
P=n-abs(n-I)
m=0
for(l in I)if(any(combn(I,l,function(i)all(P[i[c(1,k<-L(i))]]==1,n%in%i,L(unique(P[i]))==k-1,diff(i)<=x[P][i[-k]])))){m=l;break}
cat(m-1)

Моделювання:

1: 2 4 2 2 3 4 2 2   # everything after 1: is read from stdin
6                    # output is printed to stdout

1: 1 0               # everything after 1: is read from stdin
-1                   # output is printed to stdout

Де-гольф:

x = scan(nlines = 1)       # reads from stdin
n = length(x)
index    = 1:(2*n-1)       # 1  2  3  4  5  6  7  8  9 10 11 12 13 14 15
position = c(1:n, (n-1):1) # 1  2  3  4  5  6  7  8  7  6  5  4  3  2  1
value    = x[position]     # 2  4  2  2  3  4  2  2  2  4  3  2  2  4  2
is_valid_path = function(subindex) {
  k = length(subindex)
  position[subindex[1]] == 1                  & # starts at 1
  position[subindex[k]] == 1                  & # ends at 1
  n %in% subindex                             & # goes through n (end of vector)
  length(unique(position[subindex])) == k - 1 & # visits each index once (except 1)
  all(diff(subindex) <= value[subindex[-k]])
}
min_length = 0
for(len in index) {
  valid_paths = combn(index, len, FUN = is_valid_path)
  if (any(valid_paths)) {
    min_length = len
    break
  }
}
min_jumps = min_length - 1
cat(min_jumps)             # outputs to stout

2

Пітон 271

це моє рішення:

## To simplify the process we unfold the forward-backward sequence
def unfold(L): return L + L[:-1][::-1]

## Possible jumps from a given L[i] position
def AvailableJumps(L,i): return range(1,L[i]+1)

# To disable a used position, in the forward and backward sites
# (the first one is not really necessary)
def Use(L,i):
    L[i] = 0
    L[ len(L) - i - 1] = 0
    return L

def Jumps(L,i,n,S):
    if (i >= len(L)-1): 
        S.append(n)
    else:
        Laux = list(L)
        Use(Laux,i)
        for j in AvailableJumps(L,i):
            Jumps(Laux,i+j,n+1,S)

def MiniJump(L):
    S = []        
    Jumps(unfold(L),0,0,S)
    return min(S) if (S) else -1

Приклади:

print MiniJump([2,4,2,2,3,4,2,2])
print MiniJump([0,2,4,2,2,3,4,2,2])

А це (частково на сьогоднішній день) версії для гольфу:

def J(L,i,n,S):
    if (i >= len(L)-1): S.append(n)
    else:
        La = list(L)
        La[len(La) - i - 1] = 0
        for j in range(1,L[i]+1):
            J(La,i+j,n+1,S)

def MJ(L):
     S = []        
     J(L + L[:-1][::-1],0,0,S)
     return min(S) if (S) else -1

Деякі приклади:

print MJ([2,4,2,2,3,4,2,2])
print MJ([0,2,4,2,2,3,4,2,2])
print MJ([3,4,0,0,6])

Неправильно. На вході [1] вихід повинен бути 0 (вихід 1). На вході [3,0,0,1,4], вихід повинен бути 3 (ваш вихід -1)
Кодування людина

@ Кодова людина: На жаль, вибачте. Була перевірка стрибка на експорт. якщо (i> = len (L) -1): S.append (n), здається, вирішує проблему
Тріада

Все-таки дають неправильні результати. Наприклад: [2,0] ---> 1 (має бути -1).
Кодування людина

@ Кодируюча людина: Я думаю, що моє рішення суперечить принципу "Таким чином, повинно бути зрозуміло, що завжди можна перестрибнути з останньої позиції." вона стрибає через кінець.
Тріада

1
Прошу вибачення за всі ці помилки. Рядок "Таким чином, повинно бути зрозуміло, що завжди можна стрибати з останньої позиції". було видалено. Він використовувався просто для того, щоб остання позиція ніколи не була використана, коли ми рухаємось вперед у послідовності. Отже, його завжди можна використовувати для стрибків, коли ми рухаємось назад. Але, у [2,0] значення на останній позиції дорівнює 0, ви можете здійснити стрибок у максимум 0 ходів. Отже, ви ніколи не зможете досягти вихідного положення. Питання оновлено.
Кодування людини

2

Рубін - 246

a=gets.split.map &:to_i
L=a.size;r=[];a.collect!{|v|([1,v].min..v).to_a};S=a[0].product *a[1..-1];S.each{|s|i=0;b=L==1&&s[i]!=0 ?0:1;(L*2).times{|c|r<<c if i==L-1&&b==0;break if !s[i]||s[i]==0;if i==L-1;b=i=0;s.reverse!end;i+=s[i]}}
puts r.min||-1

Моделювання:

2, 4, 2, 2, 3, 4, 2, 2
6

0, 2, 4, 2, 2, 3, 4, 2, 2
-1

0
-1

1
0

2

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

Щоб зрозуміти, як це працює, я включив коментарі, які показують, як певним рядком (u = "2 1 4 3 0 3 4 4 3 5 0 3") маніпулює. Я перелічую комбінації "скель у потоці", які можна скакати. Вони представлені двійковим рядком. Я даю приклад 0b0101101010 в коментарях і показую, як це було б використано. 1 відповідають положенням скель, доступних для початкової поїздки; 0 для зворотної поїздки. Для кожного такого розподілу я використовую динамічне програмування, щоб визначити мінімальну кількість стрибків, необхідних у кожному напрямку. Я також виконую кілька простих оптимізацій для усунення деяких комбінацій на початку.

Я запускав це з рядками, наведеними в інших відповідях, і отримую ті самі результати. Ось деякі результати, які я отримав:

"2 1 4 3 0 3 4 4 3 5 0 3"                             # =>  8
"3 4 3 5 6 4 7 4 3 1 5 6 4 3 1 4"                     # =>  7
"2 3 2 4 5 3 6 3 2 0 4 5 3 2 0 3"                     # => 10
"3 4 3 0 4 3 4 4 5 3 5 3 0 4 3 3 0 3"                 # => 11
"2 3 2 4 5 3 6 3 2 0 4 5 3 2 0 3 4 1 6 3 8 2 0 5 2 3" # => 14

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

"3 4 3 0 4 3 4 4 5 3 5 3 0 4 3 3 0 3 4 5 3 2 0 3 4 1 6 3 2 0 4 5 3 2 0 3 4 1 6 3 0 4 3 4 4 5 0 1"

Код наступним чином.

I=99 # infinity - unlikely we'll attempt to solve problems with more than 48 rocks to step on

def leap!(u)
  p = u.split.map(&:to_i) # p = [2,1,4,3,0,3,4,4,3,5,0,3]
  s = p.shift        # s=2, p =   [1,4,3,0,3,4,4,3,5,0,3] # start
  f = p.pop          # f=3, p =   [1,4,3,0,3,4,4,3,5,0]   # finish
  q = p.reverse      #      q =   [0,5,3,4,4,3,0,3,4,1]   # reverse order
  # No path if cannot get to a non-zero rock from s or f
  return -1 if t(p,s) || t(q,f) 
  @n=p.size                  # 10 rocks in the stream
  r = 2**@n                  # 10000000000 - 11 binary digits 
  j = s > @n ? 0 : 2**(@n-s) #   100000000 for s = 2 (cannot leave start if combo number is smaller than j)
  k=r-1                      #  1111111111 - 10 binary digits

  b=I # best number of hops so far (s->f + f->s), initialized to infinity
  (j..k).each do |c|
    # Representative combo: 0b0101101010, convert to array
    c += r                     # 0b10 1 0 1 1 0 1 0 1 0
    c = c.to_s(2).split('').map(&:to_i)
                               # [1,0,1,0,1,1,0,1,0,1,0]
    c.shift                    #   [0,1,0,1,1,0,1,0,1,0] s->f: rock offsets available: 1,3,4,6,8
    d = c.map {|e|1-e}.reverse #   [1,0,1,0,1,0,0,1,0,1] f->s: rock offsets available: 0,2,5,7,9
    c = z(c,p)                 #   [0,4,0,0,3,0,4,0,5,0] s->f: max hops by offset for combo c
    d = z(d,q)                 #   [0,0,3,0,4,0,0,3,0,1] f->s: max hops by offset for combo c
    # Skip combo if cannot get from to a rock from f, or can't
    # get to the end (can always get to a rock from s if s > 0).
    next if [s,f,l(c),l(d)].max < @n && t(d,f)
    # Compute sum of smallest number of hops from s to f and back to s,
    # for combo c, and save it if it is the best solution so far.
    b = [b, m([s]+c) + m([f]+d)].min
  end
  b < I ? b : -1 # return result
end

# t(w,n) returns true if can conclude cannot get from sourch n to destination  
def t(w,n) n==0 || (w[0,n].max==0 && n < @n) end
def l(w) w.map.with_index {|e,i|i+e}.max end
def z(c,p) c.zip(p).map {|x,y| x*y} end

def m(p)
  # for s->f: p = [2,0,4,0,0,3,0,4,0,5,0] - can be on rock offsets 2,5,7,9
  # for f->s: p = [3,0,0,3,0,4,0,0,3,0,1] - can be on rock offsets 3,5,8,10
  a=[{d: 0,i: @n+1}]
  (0..@n).each do |j|
    i=@n-j
    v=p[i] 
    if v > 0
      b=[I]
      a.each{|h| i+v < h[:i] ? break : b << (1 + h[:d])}
      m = b.min
      a.unshift({d: m,i: i}) if m < I
    end
  end
  h = a.shift
  return h[:i]>0 ? I : h[:d]
end

0

Haskell, 173 166 байт, 159 байт у GHCi

Ось звичайна версія:

імпортувати Data.List

t=length
j[_]=0
j l=y[t f|f<-fst.span(>0)<$>permutations[0..t l-1],u<-f,u==t l-1,all(\(a,b)->abs(b-a)<=l!!a)$zip(0:f)$f++[0]]
y[]=0-1
y l=minimum l+1

Ось відповідь GHCi (покладіть рядок по черзі):

t=length
y[]=0-1;y l=minimum l+1
j[_]=0;j l=y[t f|f<-fst.span(>0)<$>Data.List.permutations[0..t l-1],u<-f,u==t l-1,all(\(a,b)->abs(b-a)<=l!!a)$zip(0:f)$f++[0]]

Просто груба сила. Створіть можливу відповідь. (тобто перестановка [0..n-1] з нулем та наступним елементом випала. Потім перевірте, чи відповідь правильна. Отримайте мінімальну довжину та додайте одиницю. (Оскільки видаляються провідні та кінцеві нулі).

Як користуватися: j[3,4,0,0,6]->3


Data.List.permutationsпрацює не в GHC, а лише в GHCi. Відповідно до нашого Посібника з правил гольфу в Хаскеллі , вам слід додати імпорт або позначити свою відповідь як "Haskell GHCi". Перший варіант, як правило, віддають перевагу гольфістам Haskell на цьому сайті.
Лайконі

Замість цього a<-permutations[0..t l-1],let f=takeWhile(/=0)aможна написати f<-map(takeWhile(/=0))(permutations[0..t l-1]), до чого знову можна пограти в гольф f<-fst.span(>0)<$>permutations[0..t l-1]. З цим ви повернулися до 166 байт, навіть додавши імпорт: Спробуйте в Інтернеті!
Лайконі
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.