상세 컨텐츠

본문 제목

[백준 21315번] 카드 섞기(파이썬)

알고리즘 공부

by Tabris4547 2022. 7. 13. 11:05

본문

728x90

https://www.acmicpc.net/problem/21315

 

21315번: 카드 섞기

마술사 영재는 카드 더미를 이용한 마술을 개발하였다. 카드들에는 1부터 N까지의 숫자가 적혀있으며 초기 상태에는 1이 맨 위에 있으며 N개의 카드가 번호 순서대로 쌓여있다. 영재는 마술을

www.acmicpc.net

처음에 문제를 읽고

이게 무슨말인지 이해가 되질 않았습니다.

카드를 섞는데

K가 왜 첫번째와 두번쨰가 있지?

 

이 문제를 다시 분해해보면

 

1. K 하나를 뽑아서 카드를 섞음

2. 근데 그걸 2번 한다.

3. 입력값은 카드를 그 2번 섞은 결과값이다.

 

이 문제에서 구현해줄 것은 

크게 두 개로 나눴습니다.

 

1. K의 경우의 수

-->일반적으로 순열,조합을 떠올리기 쉽습니다.

하지만 이 경우에는

'모든 경우'를 다 구해야합니다.

순열,조합에서는 1,2 2,1 이렇게는 되지만

1 1, 2 2 이런 조합은 되지 않습니다.

그래서 K가 될 수 있는 범위를 구하고

그 범위내에서 둘 씩 묶어줍니다.

 

2. 카드 섞기

-->저는 쌩 구현으로 시작했습니다.

먼저, 현재 배열에서

뒤에서 부터 2^k만큼을 pop해주고

앞에다가 insert해줍니다.

이 때, 옮겨준 숫자는 pre라는 리스트에 넣어줬죠.

그 뒤에는 k를 계속 2로 나누면서

pre뒤의 2^k만큼의 수를 pop하고 앞에다 넣기를 반복.

 

 

#백준 21315번 카드 섞기
from copy import deepcopy

N=int(input())

first=[i for i in range(1,N+1)]
last=list(map(int,input().split()))
#K의 범위를 알아보자
Ks=[]
num=1
while 2**num<N:
    Ks.append(num)
    num+=1
#K 조합의 모든 경우를 입력한다
case=[]
answer=[]
for i in range(len(Ks)):
    for j in range(len(Ks)):
        tmp=[]
        tmp.append(Ks[i])
        tmp.append(Ks[j])
        case.append(tmp)
#조합대로 쭉 보다
for c in case:
    #초반에는 first(1~N까지의 배열)로 넣어준다
    new=deepcopy(first)
    for now in c:
        #현재 K값만큼, 뒤에있는 걸 받고 앞으로 넣어준다
        pre=[]
        catch=2**now
        for _ in range(catch):
            pre.append(new.pop())

        for i in range(len(pre)):
            new.insert(0,pre[i])
        catch//=2
        #계속 2씩 나누면서 이전꺼에서 뒤에 있는 숫자를 규칙에 따라 받아줌
        while catch>0:
            new_pre=[]
            for _ in range(catch):
                new_pre.append(pre.pop(0))
            n=len(new_pre)
            for i in range(n):
                #해당 숫자를 찾아서 pop해주고 다시 앞에다가 insert
                p=new_pre[i]
                ind=new.index(p)
                new.pop(ind)
                new.insert(0,p)

            pre=new_pre
            catch//=2
    #만약 입력한 last와 같다면 답으로 받아준다.
    no=True
    for x in range(N):
        if not new[x]==last[x]:
            no=False
            break
    if no==True:
        answer=c
print(*answer)

 

특별한 규칙이 생각나지 않을 때는

먼저 쌩구현으로 시도하고

뒤에 시간초과등의 이슈가 생긴다면

dfs bfs 등등

다른 알고리즘을 적용해보면 좋겠다는 교훈을 얻었습니다.

728x90

관련글 더보기

댓글 영역

Tabris4547님의
글이 좋았다면 응원을 보내주세요!