最小跳数


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反例吗?
Daniel Lubarov

@Daniel编号。跳转数将等于该位置存储的值。最后一个位置始终是可以从其跳下来的候选位置,因为该位置以前未用于跳过。
编码人员

1
此描述令人困惑,因为“跳转”用于表示两种不同的含义,并且仅以一个实际示例为例,很难确定哪种含义与哪种用法相符。我希望有一个描述,例如“跳跃”和“动作”。使用这种术语,您会说每个动作都包含一定数量的跳跃。输入中的数字提供最大的跳数,输出可以明确地描述为报告最小移动数。
面包箱

1
获奖标准是什么?在标记代码高尔夫球以及代码挑战时,还不清楚。
霍华德

@breadbox是的。我同意,它含糊不清。我将尽快更新问题。
编码人员

Answers:


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←⎕

测试用例

      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

Mathematica,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

Mathematica 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

Python 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

Python 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)似乎解决了问题
Triadic 2013年

仍然给出错误的输出。例如:[2,0] ---> 1(应为-1)。
编码人员

@编码人:我认为我的解决方案与“因此,很明显,一个人总是可以从最后一个位置跳起来。”相冲突,因为我认为[2,0]-> 1是一个有效的解决方案,因为它跳到对面的结束。
Triadic

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字节,GHCi中的159字节

这是普通版本:

导入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的高尔夫规则指南,您应该添加导入内容或将答案标记为“ Haskell GHCi”。在该站点上,Haskell高尔夫球手通常首选第一个选项。
Laikoni'1

取而代之的是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字节:在线尝试!
Laikoni'1
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.