0817 upside down cake problem

ph
Admin (토론 | 기여)님의 2017년 8월 17일 (목) 22:05 판
(차이) ← 이전 판 | 최신판 (차이) | 다음 판 → (차이)
이동: 둘러보기, 검색

문제 : [1]

풀이 : [2]

문제설명 일러스트도 좋고 (적당한?) 해설도 있다.

핵심은, ① 케이크를 잘라서 flip한 뒤 다시 꼽으면 조각의 순서가 바뀐다는 것, ② angle 크기 \(x\)로 케이크를 잘라나가다 보면 정확히 \(2\pi\)의 배수가 아닌 한 어느정도 남게 되어 있는데 이를 \(b\)라 하고, \(x=a+b\)로 놓으면, \( xk = (a+b)k = 2\pi + b\). 즉, \(ka + (k-1)b = 2\pi\) 이므로 케이크 하나(\(=2\pi\))는 \(a\)크기의 조각 \(k\)개와 \(b\)크기의 조각 \(k-1\)개로 이루어진다는 것, ③ 따라서 어떻게 잘라 나가도 인접한 \(a\)두개가 존재한다는 것.

def cakeflip(x):
    # invert and reverse 
    x = np.array(x)
    if x[0]+x[1] != 1: # [1,0], [0,1] are isomorphic
        tmp = (x[1]+1)%2
        x[1] = (x[0]+1)%2
        x[0] = tmp
    return np.append(x[2:],x[0:2])

import numpy as np
for a in range(2,4):
    print '-'*40
    arr = np.zeros(a+a-1, dtype=np.uint8)
    #first filp
    arr[-2:] = 1
    cnt=1
    while np.any(arr):
        print cnt, "\t", arr
        arr = cakeflip(arr)
        cnt += 1
    print cnt, "\t", arr
    assert ((a*2-1)**2 - 1 )/2 == cnt
    # cnt = 2*n*(n-1) = (len(arr)^2 - 1) / 2
    # https://oeis.org/A046092
    # why? can you prove?
    
def simple_cakeflip(arr):
    return (len(arr)**2 - 1 )/2

def cakeflip2(x, idx=0):
    lx = len(x)
    assert lx>1
    idx0 = idx % lx
    idx1 = (idx+1) % lx
    if x[idx0] + x[idx1] == 1: #[0,1] or [1,0] are stable.
        return x 
    x0 = (x[idx1]+1)%2
    x[idx1] = (x[idx0]+1)%2
    x[idx0] = x0
    return x

for a in range(2,4):
    print '-'*40
    arr = np.zeros(a+a-1, dtype=np.uint8)
    idx = 0
    cnt = 0
    while cnt < 1 or np.any(arr):
        print cnt,"\t",arr
        arr = cakeflip2(arr, idx)
        idx += 2
        cnt += 1
    print cnt,"\t",arr
    assert cnt == simple_cakeflip(arr)
----------------------------------------
0 	[0 0 0]
1 	[1 1 0]
2 	[1 1 0]
3 	[1 1 0]
4 	[0 0 0]
----------------------------------------
0 	[0 0 0 0 0]
1 	[1 1 0 0 0]
2 	[1 1 1 1 0]
3 	[1 1 1 1 0]
4 	[1 0 0 1 0]
5 	[1 0 0 1 0]
6 	[1 0 0 1 0]
7 	[1 0 0 1 0]
8 	[1 0 0 1 0]
9 	[1 1 1 1 0]
10 	[1 1 1 1 0]
11 	[0 0 1 1 0]
12 	[0 0 0 0 0]
----------------------------------------
0 	[0 0 0 0 0 0 0]
1 	[1 1 0 0 0 0 0]
2 	[1 1 1 1 0 0 0]
3 	[1 1 1 1 1 1 0]
4 	[1 1 1 1 1 1 0]
5 	[1 0 0 1 1 1 0]
6 	[1 0 0 0 0 1 0]
7 	[1 0 0 0 0 1 0]
8 	[1 0 0 0 0 1 0]
9 	[1 0 1 1 0 1 0]
10 	[1 0 1 1 0 1 0]
11 	[1 0 1 1 0 1 0]
12 	[1 0 1 1 0 1 0]
13 	[1 0 1 1 0 1 0]
14 	[1 0 1 1 0 1 0]
15 	[1 0 1 1 0 1 0]
16 	[1 0 0 0 0 1 0]
17 	[1 0 0 0 0 1 0]
18 	[1 0 0 0 0 1 0]
19 	[1 1 1 0 0 1 0]
20 	[1 1 1 1 1 1 0]
21 	[1 1 1 1 1 1 0]
22 	[0 0 1 1 1 1 0]
23 	[0 0 0 0 1 1 0]
24 	[0 0 0 0 0 0 0]

대충 규칙을 알아내는 것은 어렵지 않다. 홀수개의 조각만으로 나뉘는데 차례로 두개씩 뒤집으면 언젠가 제자리로 돌아올 것이라는 것도 대강 이해할 수 있다. 그런데 왜 모든 permutation이 아니고 A046092인지 예제출력을 좀 봐도 쉽게 증명을 못하겠다.

아 물론 projecteuler에 나온 최초의 문제도 아직 미해결상태고. #cont



blog comments powered by Disqus