금 사슬을 잘라


32

여행자는 도시 외곽 호텔에서 n 일 동안 숙박해야 합니다. 현금이 부족하고 신용 카드가 만료되었습니다. 그러나 그는 n 과 금 사슬을 가지고 링크 있습니다.

이 호텔의 규칙은 주민들이 매일 아침 집세를 내야한다는 것입니다. 여행자는 관리자와 계약을 맺고 매일 골든 체인의 링크 하나를 지불합니다. 그러나 관리자는 여행자가 매일 지불하면서 체인에 최소한의 손상을 입히도록 요구합니다. 다시 말해, 가능한 적은 링크를 줄일 수있는 솔루션을 고안해야합니다.

링크를 자르면 3 개의 서브 체인이 만들어집니다. 하나는 절단 링크 만 포함하고 다른 하나는 각면에 있습니다. 예를 들어, 길이가 8 인 체인의 세 번째 링크를 절단하면 길이가 [2, 1, 5] 인 하위 체인이 생성됩니다. 관리자는 기꺼이 변경하여 여행자는 첫 번째 날을 길이 1 체인으로 지불 한 다음 두 번째 날을 길이 2 체인으로 지불하여 첫 번째 체인을 되 찾을 수 있습니다.

코드는 길이 n을 입력하고 최소 길이를 잘라 내기위한 링크 목록을 출력해야합니다.

규칙 :

  • n 은 0보다 큰 정수입니다.
  • 링크에 0 기반 또는 1 기반 색인을 사용할 수 있습니다.
  • 일부 숫자의 경우 솔루션이 고유하지 않습니다. 예를 들어, n = 15[3, 8][4, 8]유효한 출력한다.
  • 목록을 반환하거나 적절한 구분 기호로 인쇄하십시오.
  • 이것은 이므로 바이트 단위의 가장 짧은 코드가 이깁니다.

테스트 사례 :

Input          Output (1-indexed)
1              []
3              [1]
7              [3]
15             [3, 8]
149            [6, 17, 38, 79]

자세한 예

들면 N 링크 (3) 및 길이가 8 개 subchains 결과 절단 = 15 [2, 1, 4, 1, 7]. 다음과 같은 이유로 유효한 솔루션입니다.

 1 = 1
 2 = 2
 3 = 1+2
 4 = 4
 5 = 1+4
 6 = 2+4
 7 = 7
 8 = 1+7
 9 = 2+7
10 = 1+2+7
11 = 4+7
12 = 1+4+7
13 = 2+4+7
14 = 1+2+4+7
15 = 1+1+2+4+7

한 번의 절단 만있는 솔루션이 없으므로 최적의 솔루션입니다.

추가

이 문제는 정수 파티셔닝과 관련이 있습니다. 1에서 n 까지의 모든 정수 가 P 의 하위 집합 인 하나 이상의 패션을 갖도록 n 의 파티션 P 를 찾고 있습니다.

여기의 YouTube 동영상 이 문제에 대한 하나의 가능한 알고리즘에 대한이.


귀하의 "변경"참조를 이해하지 못합니다. 게시 된 예에서 두 번째 날에는 2 링크 체인으로 지불하고 설명에 따라 변경 사항으로 1 링크 체인 (전날 지불 한 것을 다시 가져옵니다). 그러나 셋째 날에는으로 지불합니다 1+2. 두 번째 2 링크 체인은 어디에서 왔습니까?
11

4
@Flater 관리자가 이미 가지고 있습니다. 추가 비용을 지불하면됩니다. 실제로 RHS는 관리자가 매일 소유하는 링크입니다.
polfosol ఠ_ఠ

답변:


15

05AB1E , 23 11 8 바이트

ΔÍN-;иg=

온라인으로 사용해보십시오!

0 기반 인덱싱을 사용합니다.

설명:

             # start from the implicit input
Δ            # loop forever
 Í           # subtract 2
  N-         # subtract the current iteration number
    ;        # divide by 2
     и       # create a list of length x
      g      # get the length of the list
       =     # print

иgnoop처럼 보이지만 실제로 두 가지 유용한 작업을 수행합니다. 정수로 자르고 ( ;float를 반환) x가 음수이면 인터프리터와 충돌합니다 (유일한 종료 조건 임).


23 바이트 솔루션은 매우 다른 접근 방식을 사용, 그래서 여기가 후세를위한 것입니다 ÅœʒR2äθP}ʒæOê¥P}θ2äθη€O( TIO , 설명 ).


2
답변을 삭제했습니다. 나의 것은 42 살이고 11 살은 너의 창피함을 느끼기에는 너무 큰 차이이다. ;) 그래도 좋은 대답이고,에서 lol Ø.Ø. 바닥을 모두 만들고 모든 음화를에 매핑하기 위해 임의의 것을 시도 했습니까 -1? 어쨌든, 아주 좋은 대답과 내가 예상했던 것보다 훨씬 짧습니다. 나쁜 42 바이트를 게시 한 후 약 20 바이트를 생각하고있었습니다.
케빈 크루이 ssen

2
@KevinCruijssen Nnope Ø.Ø는 실제로 내 첫 아이디어였습니다. 귀하의 의견은 임의 것을 시도 나에게 영감 : 내가 발견 ®Ÿà, ï®M그리고 더 중요한 것은, иg이 좋은 8 byter를 산출한다. 나는 항상 osabie가 많은 경우 (div by 0, 잘못된 유형 등) 충돌보다 아무것도하지 않는 것을 선호 하므로이 충돌이 유용 할 것입니다.
그리미

2
Hehe, 05AB1E는 결코 충돌하지 않아야하지만, 때때로는 전혀 짜증나 지 않을 것입니다. 레거시에서는 충돌하는 방법조차 몰랐습니다. 과거에는 제로 오류 우리는 수동으로 호출 할 수 있습니다. xD 새로운 버전에서는 특정 내장에 잘못된 인수를 줄 때 여전히 오류와 함께 충돌합니다. 그리고 다시 좋은 -3.
케빈 크루이 ssen

2
"x가 음수이면 인터프리터를 손상시킵니다 (이것이 유일한 종료 조건입니다)." -사랑합니다
John Dvorak

9

파이썬 2 , 75 바이트

f=lambda n,i=0:n>=i<<i and f(n,i+1)or[min(n,2**j*i-i+j)for j in range(1,i)]

온라인으로 사용해보십시오!


설명:

기본 숫자가 컷 수와 일치하는 일련의 '이진'청크를 작성합니다.

예 :

63 3 컷으로 수행 할 수 있습니다.베이스 4의 파티션을 의미합니다 (3 개의 단일 링이 있으므로).

컷 : 5, 14, 31, 체인을 제공합니다4 1 8 1 16 1 32 (정렬1 1 1 4 8 16 32 .

모든 번호를 만들 수 있습니다 :

1       1
2       1 1
3       1 1 1
4       4
...
42      1 1 8 32
...
62      1 1 4 8 16 32
63      1 1 1 4 8 16 32

다른 예 :

18: 4,11        ->  3 1 6 1 7
27: 5,14,27     ->  4 1 8 1 13 1
36: 5,14,31     ->  4 1 8 1 16 1 5
86: 6,17,38,79  ->  5 1 10 1 20 1 40 1 7

1
f=시작에 추가해서는 안 됩니까? f람다 함수에서 호출을 사용하기 때문에 정의하는 것과 동일한 람다를 참조한다고 가정 할 수 있습니다.
randomdude999

@ randomdude999, 네, 잊어 버렸습니다 ...
TFeld

@ randomdude999이 규칙은 모든 언어 또는 파이썬에만 적용됩니까? 나는이 도전에서 순수한 람다 인 자바 스크립트 답변을 본다…
Shadow

3
@Shadow 모든 언어에 적용되지만 재귀 적 람다에만 적용됩니다.
TFeld

1
@Shadow 더 일반적인 규칙은 과제에서 명시 적으로 허용하지 않는 한 코드에서 정의되지 않았거나 언어로 전역 적으로 정의되지 않은 것을 참조 할 수 없다는 것입니다. 가장 일반적인 경우는 재귀 함수이지만 다른 상황에도 적용됩니다. 이 대답 은 또 다른 예입니다. f재귀하지는 않지만 코드에서 참조되므로 이름을 지정해야합니다.
Arnauld

8

R , 77 69 바이트

Aaron Hayman 덕분에 -8 바이트

pmin(n<-scan(),0:(k=sum((a=2:n)*2^a<=n))+cumsum((k+2)*2^(0:k))+1)[-n]

온라인으로 사용해보십시오!

방해 케이 필요한 컷 수; 케이 가장 작은 정수는 (케이+1)2케이. 실제로 가능한 해결책은 길이의 하위 체인을 갖는 것입니다.1,1,,1 (케이 시간) 및 (케이+1),2(케이+1),4(케이+1),8(케이+1),,(케이+1)2케이1. 이것이 충분하고 최적인지 쉽게 확인할 수 있습니다.

(체인의 총 길이를 초과하면 마지막 하위 체인을 짧게 만들어야 할 수도 있습니다.)

Ungolfed (이전의 유사한 버전을 기반으로 함) :

n = scan()                            # read input
if(n - 1){                            # If n==1, return NULL
  k = match(F, (a = 2:n) * 2 ^ a > n) # compute k
  b = (k + 1) * 2 ^ (1:k - 1)         # lengths of subchains
  c = 1:k + cumsum(b)                 # positions of cuts
  pmin(c, n )                         # if last value is >n, coerce it to n
}

(의 가치를 증명 케이 내가 말한대로 : 케이컷. 우리는 다음케이 단위 서브 체인, 그래서 우리는 첫 번째 서브 체인 길이가 필요합니다 케이+1. 이제 모든 길이를 처리 할 수 ​​있습니다2케이+1그래서 우리는 길이가 길어야합니다. 2케이+2그런 다음 4케이+4... 따라서 우리가 얻을 수있는 최대치 케이 컷은 길이를 모두 합하여 얻습니다. (케이+1)2케이1.)

만약 에이(케이) 가장 작은 정수 요구 케이 인하 에이(케이)이다 OEIS A134401는 .


I doubt it would help with the special case for n=1, but an alternative way to generate the cutoffs is the recurrence 1, 4, 4a(n-1)-4a(n-2).
Peter Taylor

@PeterTaylor I had a similar recurrence for computing k; this corresponds to OEIS A134401: oeis.org/A134401 But my implementation of the recurrence relation takes up more bytes than the current code.
Robin Ryder

약간의 재 배열이 73으로 줄었 습니다. 온라인으로 사용해보십시오!
Aaron Hayman

트윗 담아 가기 sum대신을 (를) 사용하여 스마트 이동 match합니다.
로빈 라이더

69 바이트와 당신을 화나게하는 if 문을 제거 했습니다
Aaron Hayman



2

C ++, 109,107 바이트

Kevin 덕분에 -2 바이트

#include<iostream>
main(){int n,k=0;for(std::cin>>n;++k<<k<n;);for(n-=k;n>0;k*=2,n-=k+1)std::cout<<n<<',';}

이 알고리즘은 Robin Ryder의 답변과 비슷합니다. 코드는 컴파일 가능한 전체 형식으로 작성됩니다.시도 해봐!

세부:

std::cin>>n;               // get the value of n as input
while(++k<<k<n);           // determine k
for(n-=k;n>0;k*=2,n-=k+1)  // we don't need n, so the lengths...
    std::cout<<n<<' ';     // of links are subtracted repeatedly

바이트 길이가 동일한 C 변형 이 있습니다 (별도의 답변이 필요하지 않은 것 같습니다).

#include<stdio.h>
main(){int n,k=0;for(scanf("%d",&n);++k<<k<n;);for(n-=k;n>0;k*=2,n-=k+1)printf("%d,",n);}

골프에 대한 두 가지 사소한 것들 : =0after k0기본적 으로 제거되므로 제거 할 수 있습니다 . std::cin>>n;while(++k<<k<n);일 수 있습니다 for(std::cin>>n;++k<<k<n;);. 나는 또한 for(n-=k;n>0;k*=2,n-=k+1)어떻게 든 재료를 결합 하여 느낌 을 단순화 할 수 있지만 어떻게 확신하지 못합니다. 추신 : 쉼표 구분 기호를 공백으로 변경하면 마지막 imo가 표시되지 않기 때문에 약간 더 좋아 보이지만 이것은 순전히
장식입니다

1
@KevinCruijssen 감사하지만 일부 컴파일러는 비 정적 변수에 기본값을 할당하지 않습니다. 그래서 나는 =0이식성이 필요 하다고 생각했다 .) 나는 또한 그 이후의 공간 #include이 필요하지 않다는 것을 깨달았다 .
polfosol ఠ_ఠ

그래. C ++을 잘 모르므로 온라인 컴파일러를 사용하여 답변을 연결하여 몇 가지를 테스트했습니다. :) 당신은 내 의견에서 제안한 두 번째 변화를 잊어 버렸습니다 : while 루프는 for 루프로 들어가고 std::cin>>n내부에 넣습니다.
케빈 크루이 ssen


1

레티 나 0.8.2 , 61 바이트

.+
11,$&$*
+`\b(1+),(\1(1*)1?\3)$
1$2¶1$1,$3
1+,
1
1A`
1+
$.&

온라인으로 사용해보십시오! @Grimy의 답변 1 색인 포트. 설명:

.+
11,$&$*

로 시작 N=2하고 입력을 단항으로 변환합니다.

+`\b(1+),(\1(1*)1?\3)$

N입력에서 빼기 를 반복 해서 2로 나눕니다.

1$2¶1$1,$3

성공하면 이전 행의 입력보다 1을 더 많이 기억 N하고 현재 행을 증가 시키고 입력을 새 값으로 업데이트하십시오.

1+,
1

N마지막 값도 제거 하고 1- 인덱싱되도록 증가시킵니다.

1A`

증가 된 원래 입력을 제거하십시오.

1+
$.&

결과를 10 진수로 변환하십시오.


당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.