Nombre minimum de sauts

14

Étant donné une séquence de nombres, trouvez le nombre minimum de sauts pour aller de la position de départ à la fin et revenez à la position de départ.

Chaque élément de la séquence indique le nombre maximum de mouvements que l'on peut déplacer à partir de cette position.

À n'importe quelle position, vous pouvez effectuer un saut d'au plus k mouvements, où k est la valeur stockée à cette position. Après avoir atteint la fin, vous ne pouvez utiliser que les positions de saut qui n'ont pas été utilisées auparavant pour le saut.

L'entrée sera donnée sous la forme d'une séquence de nombres séparés par des espaces simples. La sortie doit être un nombre unique qui est le nombre minimum de sauts utilisés. S'il n'est pas possible d'aller à la fin et de revenir à la position de départ, alors imprimez -1

Contribution:

2 4 2 2 3 4 2 2

Production:

6 (3 pour atteindre la fin et 3 pour revenir)

Contribution

dix

Production

-1

Remarque

  • Supposons que tous les numéros de la séquence sont non négatifs

EDIT 1

La ligne "Ainsi, il devrait être clair que l'on peut toujours sauter de la dernière position." pourrait être déroutant, donc je l'ai retiré de la question. Cela n'aura aucun effet sur la question.

Critères gagnants:

Le gagnant sera celui avec le code le plus court.

Homme de codage
la source
3
Thus, it should be clear that one can always jump from the last position.- n'est-ce pas 1 0un contre-exemple?
Daniel Lubarov
@Daniel No. Le nombre de sauts sera égal à la valeur stockée à cette position. La dernière position est toujours un candidat à partir duquel on peut sauter puisque cette position n'était pas utilisée auparavant pour le saut.
Coding man
1
Cette description prête à confusion parce que «sauts» est utilisé pour signifier deux choses différentes, et avec un seul exemple réel, il est difficile de lever l'ambiguïté quelle signification va avec quelle utilisation. Je préférerais une description faisant référence, par exemple, aux «sauts» et aux «mouvements». Avec cette terminologie, vous diriez que chaque mouvement consiste en un certain nombre de sauts. Les nombres dans l'entrée fournissent le nombre maximum de sauts, et la sortie peut être décrite sans ambiguïté comme signalant le nombre minimum de mouvements.
boîte à pain
1
Quel est le critère gagnant? Comme vous avez étiqueté code-golf ainsi que code-challenge, ce n'est pas clair.
Howard
@breadbox Oui. Je suis d'accord, c'est ambigu. Je mettrai à jour la question bientôt.
Coding man

Réponses:

4

APL (Dyalog), 116

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

Cas de test

      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

Approche

L'approche est une recherche par force brute utilisant une fonction récursive.

À partir de la position 1, définissez la valeur à la position actuelle sur 0 et générez un tableau des positions qui peuvent être sautées à partir de la position actuelle. Passez la nouvelle position et le tableau modifié à lui-même. Les cas de base sont lorsque la valeur à la position actuelle est 0 (ne peut pas sauter) ou atteint la fin.

Ensuite, pour chacun des tableaux générés, inversez-le et recommencez la recherche. Étant donné que les positions sautées sont définies sur 0, nous ne pouvons plus sauter à partir de là.

Pour les tableaux que nous avons atteint à la fin, trouvez ceux qui ont le nombre minimum de 0. En soustrayant le nombre de 0 dans le tableau initial donne le nombre réel de sauts effectués.

TwiNight
la source
4

Mathematica, 197 193 caractères

Force brute.

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 
alephalpha
la source
Travail très impressionnant. C'est peut-être de la force brute, mais c'est quand même très élégant.
DavidC
3

Mathematica 351

[Remarque: Ce n'est pas encore entièrement joué; De plus, l'entrée doit être ajustée pour s'adapter au format requis. Et la règle de ne pas sauter sur la même position deux fois doit être mise en œuvre. Il existe également des problèmes de formatage de code qui doivent être résolus. Mais c'est un début.]

Un graphe est construit avec des nœuds correspondant à chaque position, c'est-à-dire chaque chiffre d'entrée représentant un saut. DirectedEdge[node1, node2]signifie qu'il est possible de passer du nœud 1 au nœud 2. Les chemins les plus courts sont trouvés du début à la fin, puis de la fin au début.

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

Usage

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

6
3
-1

DavidC
la source
C'est partiellement faux car cela n'applique pas la règle du non-saut sur un nombre double, mais c'est un début, donc je vais voter pour cela. Je n'avais aucune idée si c'était même possible :)
Poignée de porte
Vous avez raison. J'ai ignoré la règle du non-saut sur un nombre deux fois Demain, je vais essayer de corriger cela.
DavidC
3

Python 304

Je pense que cette nouvelle approche résout (j'espère!) Tous les problèmes concernant le cas [2,0] et similaire:

Dans cette version, la séquence d'entrée est parcourue (si possible) jusqu'à la fin, puis nous recommençons le processus avec la séquence inversée. Nous pouvons maintenant garantir que pour chaque solution valide l'un des sauts atterrit sur le dernier élément.

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

Ce sont les versions golfées:

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

Et quelques exemples:

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
Triadic
la source
Possède un énorme potentiel pour continuer à jouer au golf. Mais il n'y a pas de gestion des entrées et sorties, ce qui fait partie de ce problème.
Rétablir Monica
1
vous avez des tonnes d'espaces blancs inutiles ...
Poignée de porte
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)

Simulation:

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

De-golfé:

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
flodel
la source
2

Python 271

c'est ma solution:

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

Exemples:

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

Et ce sont les versions golfées (en partie maintenant):

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

Quelques exemples:

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])
Triadic
la source
Faux. À l'entrée [1], la sortie doit être 0 (votre sortie est 1). À l'entrée [3,0,0,1,4], la sortie devrait être 3 (votre sortie est -1)
Coding man
@Coding man: Oups, désolé. Il y avait un contrôle de saut exrtra. si (i> = len (L) -1): S.append (n) semble résoudre le problème
Triadic
Donne toujours de mauvaises sorties. Ex: [2,0] ---> 1 (devrait être -1).
Coding man
@Coding man: Je pense que ma solution est en conflit avec le "Ainsi, il devrait être clair que l'on peut toujours sauter de la dernière position.", Car je considère que [2,0] ---> 1 est une solution valide, car il saute à travers la fin.
Triadic du
1
Je m'excuse pour toutes ces erreurs. La ligne "Ainsi, il devrait être clair que l'on peut toujours sauter de la dernière position." a été retiré. Il a été utilisé simplement pour signifier que la dernière position n'a jamais été utilisée lorsque nous avançons dans la séquence. Ainsi, il peut toujours être utilisé pour sauter lorsque nous reculons. Mais, dans [2,0], la valeur à la dernière position est 0, vous pouvez faire un saut d'au maximum 0 coups. Par conséquent, vous ne pouvez jamais atteindre la position de départ. La question a été mise à jour.
Coding man
2

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

Simulation:

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

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

0
-1

1
0
Thaha kp
la source
2

Ruby - environ 700 golfés. J'ai commencé une version golfée, avec des noms à un caractère pour les variables et les méthodes, mais après un certain temps, je me suis plus intéressé à l'algorithme qu'au golf, j'ai donc arrêté d'essayer d'optimiser la longueur du code. Je ne m'inquiétais pas non plus d'obtenir la chaîne d'entrée. Mon effort est ci-dessous.

Pour vous aider à comprendre comment cela fonctionne, j'ai inclus des commentaires qui montrent comment une chaîne particulière (u = "2 1 4 3 0 3 4 4 3 5 0 3") est manipulée. J'énumère des combinaisons de "roches dans le ruisseau" qui sont disponibles pour sauter. Ceux-ci sont représentés par une chaîne binaire. Je donne l'exemple 0b0101101010 dans les commentaires et montre comment il serait utilisé. Les 1 correspondent aux positions des roches disponibles pour le voyage initial; les 0 pour le voyage de retour. Pour chacune de ces allocations, j'utilise la programmation dynamique pour déterminer le nombre minimal de sauts requis dans chaque direction. J'effectue également quelques optimisations simples pour éliminer certaines combinaisons très tôt.

Je l'ai exécuté avec les chaînes données dans d'autres réponses et j'obtiens les mêmes résultats. Voici quelques autres résultats que j'ai obtenus:

"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

J'aimerais savoir si d'autres obtiennent les mêmes résultats pour ces chaînes. Les performances sont relativement bonnes. Par exemple, il a fallu moins d'une minute pour obtenir une solution pour cette chaîne:

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

Le code suit.

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
Cary Swoveland
la source
0

Haskell, 173 166 octets, 159 octets dans GHCi

Voici la version normale:

importer 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

Voici la réponse GHCi (mettez la ligne une à la fois):

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

Juste une bruteforce. Générez la réponse possible. (c'est-à-dire permutation de [0..n-1] avec zéro et l'élément suivant supprimés. Vérifiez ensuite si la réponse est correcte. Obtenez la longueur minimale et ajoutez par un. (Puisque les zéros de tête et de fin sont supprimés).

Comment utiliser: j[3,4,0,0,6]->3

Akangka
la source
Data.List.permutationsne fonctionne pas dans GHC, mais uniquement dans GHCi. Selon notre Guide des règles du golf à Haskell , vous devez soit ajouter l'importation, soit marquer votre réponse comme "Haskell GHCi". La première option est généralement préférée par les golfeurs Haskell sur ce site.
Laikoni
Au lieu de a<-permutations[0..t l-1],let f=takeWhile(/=0)a, vous pouvez écrire f<-map(takeWhile(/=0))(permutations[0..t l-1]), qui peut encore être joué au golf f<-fst.span(>0)<$>permutations[0..t l-1]. Avec cela, vous êtes de retour à 166 octets même en ajoutant l'importation: Essayez-le en ligne!
Laikoni