다리와 토치 문제


17

이 코드 골프 퍼즐에서 영감을 얻은 것은 Bridge and Torch 문제 인데, 이는 다리가 시작될 때 d 명의 사람들이 모두 최소한의 시간 안에 교차해야하는 문제입니다.

잡는 것은 최대 두 사람이 한 번에 교차 할 수 있다는 것입니다. 그렇지 않으면 다리가 무게로 부서 질 것이며 그룹은 다리를 건너기 위해 운반해야하는 하나의 토치에만 접근 할 수 있습니다.

전체 퍼즐의 각 사람은 다리를 건너는 데 걸리는 지정된 시간이 있습니다. 두 사람이 함께 교차하면 가장 느린 사람만큼 느리게 진행됩니다.

다리를 건너야하는 정해진 인원은 없습니다. 귀하의 솔루션은 d의 모든 값에 대해 작동해야합니다 .

이 문제에 표준 입력을 사용할 필요는 없지만 문제를 설명하기 위해 설명에 다음 입력 및 출력 형식을 사용합니다. 첫 번째 숫자 d 는 브리지 시작시의 인원 수입니다. 그런 다음 코드는 각각 사람의 속도를 나타내는 d 숫자 를 검색합니다 .

코드 출력은 브리지 시작에서 브리지 끝까지 모든 사람을 교차하는 데 필요한 최소 시간이되며 앞에서 설명한 기준을 충족합니다.

다음은 일부 입력 사례 및 출력 사례와 첫 번째 입력 사례에 대한 설명입니다. 이 정보에서 알고리즘을 도출하여 가능한 가장 적은 바이트의 코드로 문제를 해결하는 것은 사용자의 책임입니다.

입력

4
1 2 5 8

산출

15

이 결과에 도달하려면 사람들은 다음과 같은 방식으로 교차해야합니다.

A and B cross forward (2 minutes)
A returns (1 minute)
C and D cross forward (8 minutes)
B returns (2 minutes)
A and B cross forward (2 minutes)

다음은 진행 과정을 안내하는 또 다른 테스트 사례입니다.

입력

5
3 1 6 8 12

산출

29

규칙 :

  1. 입력이 정렬되지 않는다고 가정하고 직접해야합니다 (필요한 경우).
  2. 퍼즐에있는 사람의 수는 4로 고정되어 있지 않습니다 (N> = 1).
  3. 모든 그룹과 개별 건널목에는 토치가 있어야합니다. 토치가 하나만 있습니다.
  4. 각 그룹은 최대 2 명으로 구성되어야합니다!
  5. 아닙니다. 다리에서 뛰어 내려 반대편으로 헤엄 칠 수 없습니다. 이와 같은 다른 트릭은 없습니다.).

XNOR에 의해 발견 아래와 같은 테스트 케이스에 반드시 1 3 4 514하지 (15) 반환해야하는
gladed

1 4 5 6 7비슷한 문제가 있습니다. 25 대 26
Sherlock9

1
이것은 이상한 질문처럼 보이지만 퍼즐의 최소 및 최대 인원은 얼마입니까? 내 솔루션을 작업하는 동안 나는 N >= 2사람들 만 처리한다는 것을 알았습니다 (이상하게도 "1 명이 넘어야 함"의 사소한 경우를 처리하는 것이 추가 작업이라는 것을 알았 으므로이 점에 대한 명확한 설명이 좋을 것입니다. 미리 감사드립니다.
Sherlock9

@ Sherlock9 솔루션이 N> = 1에서 작동해야한다고 가정합니다.
baseman101

테스트 사례에 따르면 길이를 매개 변수로 사용할 수 있지만 규칙에서 더 명확하게 알 수 있습니까? 입력은 시간과 인원의 배열이 허용됩니까, 아니면 허용 된 시간입니까?
Sherlock9

답변:


8

파이썬 3, 100 99 바이트

재귀 솔루션

f=lambda s:s[0]+s[-1]+min(2*s[1],s[0]+s[-2])+f(s[:-2])if s.sort()or 3<len(s)else sum(s[len(s)==2:])

이 문서에 대한 @xnor에게 감사합니다

@lirtosiast save 2 bytes, @movatica save 1 bytes 및 @gladed 덕분에 이전 솔루션이 작동하지 않습니다.

다음 트릭을 사용하여 람다 함수 s.sort() or s 에서 무언가를 평가 하십시오. 여기서 우리는 정렬을 계산하고 테스트 결과를 반환합니다s.sort()or len(s)>3

언 골프

def f(s):
    s.sort()                                   # sort input in place
    if len(s)>3:                               # loop until len(s) < 3
        a = s[0]+s[-1]+min(2*s[1],s[0]+s[-2])  # minimum time according to xnor paper
        return  a + f(s[:-2])                  # recursion on remaining people
    else:
        return sum(s[len(s)==2:])              # add last times when len(s) < 3

결과

>>> f([3, 1, 6, 8, 12])
29
>>> f([1, 2, 5, 8])
15
>>> f([5])
5
>>> f([1])
1
>>> f([1, 3, 4, 5])
14

1 바이트를 저장하고 다음 len(s)==2으로 변경할 수 있습니다len(s)<3
Mr Public

@MrPublic 당신은 버그를 발견, 나는 우리가 감사로 대체 할 수없는 이유는 버그 가 s[0]*(len(s)==2)아닌 솔루션을 변경(s[0]*len(s)==2) f([1]) -> 0<3
Erwan

이 백서 는 여러 가능성의 최소 인 최적의 시간에 대한 표현을 가지고 있습니다. 모든 경우에 솔루션이 최적입니까?
xnor

@xnor 와우는 내가 보조 정리 3 식을 최적의 솔루션을 사용하는 것 같다A5:22
유안

1
@movatica 제안으로 업데이트
Erwan

4

파이썬 2 119 114 112 119 110 100 95 바이트

답변을 분리하는 것이 좋습니다.

Theorem 1, A2:09 이 논문을 사용하는 솔루션 xnor linked . 논문을 인용하려면 (제로 색인화로 변경) :The difference between C_{k-1} and C_k is 2*t_1 - t_0 - t_{N-2k}.

lambda n,t:t.sort()or(n-3)*t[0]*(n>1)+sum(t)+sum(min(0,2*t[1]-t[0]-t[~k*2])for k in range(n/2))

풀기 :

def b(n, t): # using length as an argument
    t.sort()
    z = sum(t) + (n-3) * t[0] * (n>1) # just sum(t) == t[0] if len(t) == 1
    for k in range(n/2):
        z += min(0, 2*t[1] - t[0] - t[-(k+1)*2]) # ~k == -(k+1)
    return z

길이가 인수가 될 수 있다고 가정 할 수 있습니까?
Erwan

@ Erwan 예제 테스트 사례가 허용하는 것 같습니다. 물어봐
Sherlock9

2

루비, 94 133 97 96 101 96 99 바이트

답변을 분리하는 것이 좋습니다.

이것에 설명 된 알고리즘에 기초하여 솔루션 A6:06-10다리와 토치에 문제점이 논문 .

편집 : if가 마지막에 호출 a=s[0]될 때 아직 정의되지 않은 버그 수정 .as.size <= 3

->s{r=0;(a,b,*c,d,e=s;r+=a+e+[b*2,a+d].min;*s,y,z=s)while s.sort![3];r+s.reduce(:+)-~s.size%2*s[0]}

풀기 :

def g(s)
  r = 0
  while s.sort![3]      # while s.size > 3
    a, b, *c, d, e = s  # lots of array unpacking here
    r += a + e + [b*2, a+d].min
    *s, y, z = s        # same as s=s[:-2] in Python, but using array unpacking
  end
  # returns the correct result if s.size is in [1,2,3]
  return r + s.reduce(:+) - (s.size+1)%2 * s[0]
end

1

스칼라, 113 135 (darnit)

def f(a:Seq[Int]):Int={val(s,b)=a.size->a.sorted;if(s<4)a.sum-(s+1)%2*b(0)else b(0)+Math.min(2*b(1),b(0)+b(s-2))+b(s-1)+f(b.take(s-2))}

언 골프 :

def f(a:Seq[Int]):Int = {
    val(s,b)=a.size->a.sorted      // Sort and size
    if (s<4) a.sum-(s+1)%2*b(0)    // Send the rest for cases 1-3
    else Math.min(b(0)+2*b(1)+b(s-1),2*b(0)+b(s-2)+b(s-1)) + // Yeah.
        f(b.take(s-2))             // Repeat w/o 2 worst
}

시험 장치:

val tests = Seq(Seq(9)->9, Seq(1,2,5,8)->15, Seq(1,3,4,5)->14, Seq(3,1,6,8,12)->29, Seq(1,5,1,1)->9, Seq(1,2,3,4,5,6)->22, Seq(1,2,3)->6, Seq(1,2,3,4,5,6,7)->28)
println("Failures: " + tests.filterNot(t=>f(t._1)==t._2).map(t=>t._1.toString + " returns " + f(t._1) + " not " + t._2).mkString(", "))

일반적으로 크지는 않지만 강력한 형식의 언어에는 좋지 않습니다. 그리고 내가 잡지 않은 사건을 발견 한 xnor에게 감사드립니다.


이 백서 는 여러 가능성의 최소 인 최적의 시간에 대한 표현을 가지고 있습니다. 모든 경우에 솔루션이 최적입니까?
xnor

1

루비, 104 95 93 바이트

답변을 분리하는 것이 좋습니다.

이 기반으로하는 솔루션입니다 내 파이썬이 솔루션Theorem 1, A2:09다리와 토치 문제에이 논문 .

->n,t{z=t.sort!.reduce(:+)+t[0]*(n>1?n-3:0);(n/2).times{|k|z+=[0,2*t[1]-t[0]-t[~k*2]].min};z}

풀기 :

def b(n, t) # using length as an argument
  z = t.sort!.reduce(:+) + t[0] * (n>1 ? n-3 : 0)
  (n/2).times do each |k|
    a = t[1]*2 - t[0] - t[-(k+1)*2] # ~k == -(k+1)
    z += [0, a].min
  end
  return z
end
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.