swea 3378 스타일리쉬 들여쓰기 [python]

2020. 3. 19. 15:47낙서장

문제

https://swexpertacademy.com/main/searchAll/searchMore.do?category=CODE&keyword=%EC%8A%A4%ED%83%80%EC%9D%BC%EB%A6%AC%EC%89%AC

먼저는 로그인을 해야 문제를 보고 풀 수 있다

문제 요약

현재 줄에서 괄호 갯수 차이에 따라 다음 줄 왼쪽에 " . " 이 붙는 갯수가 달라진다.

현재까지 줄에서 ( 개수를 a, ) 개수를 b, { 개수를 c, } 개수를 d, [ 개수를 e, ] 개수를 f 라고 할 떄

소괄호에는 R, 중괄호에는 C, 대괄호에는 S 를 ( 0 <= R, C, S <= 20 ) 각각 곱해서

R*(a-b) + C*(c-d) + S*(e-f) 를 들여쓰기하는 것이다.

마스터가 스타일리쉬하게 " . " 으로 들여쓰기를 한 것을 보고

"나"도 따라하려고 한다.

내가 쓴 글의 줄마다 " . " 으로 들여쓰기 해야하는 숫자를 출력해야한다.

마스터의 글을 보고 들여쓰기를 따라 할 수 없는 줄은 -1 을 출력한다.

전체 코드

from itertools import product

for t in range(1,int(input())+1):
    # 기본 입력
    p,q = map(int,input().split())
    Master = [input() for _ in 'a'*p]
    Me = [input() for _ in 'a'*q]

    # Master . 갯수, (){}[] 갯수
    a=b=c=0
    Master_dot=[]
    Master_bracket=[[0,0,0]]
    for i1 in Master:
        Master_dot.append(len(i1)-len(i1.lstrip('.')))
        for j1 in i1:
            if j1=='(':a+=1
            if j1==')':a-=1
            if j1=='{':b+=1
            if j1=='}':b-=1
            if j1=='[':c+=1
            if j1==']':c-=1
        Master_bracket.append([a,b,c])

    # R,C,S 가능성 있는 것들
    candidate=[]

    # 가능한 모든 R,C,S
    for i2 in product(range(1,21), repeat=3):
        R1,C1,S1=i2
        for j2 in range(1,p):
            a1,b1,c1=Master_bracket[j2]
            if R1*a1+C1*b1+S1*c1!=Master_dot[j2]:
                break
        else:
            candidate.append([R1,C1,S1])

    # Me (){}[] 갯수
    d=e=f=0
    Me_bracket=[]
    for i3 in Me:
        for j3 in i3:
            if j3=='(':d+=1
            if j3==')':d-=1
            if j3=='{':e+=1
            if j3=='}':e-=1
            if j3=='[':f+=1
            if j3==']':f-=1
        Me_bracket.append([d,e,f])

    # 가능성 있는 것들에 대해서 나올 수 있는 점들
    Me_dot=[set() for _ in'a'*q]
    for i4 in range(q):
        d1,e1,f1=Me_bracket[i4]

        for j4 in candidate:
            R2,C2,S2=j4
            Me_dot[i4].add(R2*d1+C2*e1+S2*f1)
        if candidate==[]:
            Me_dot[i4]=-1
        elif len(Me_dot[i4])==1:
            Me_dot[i4]=Me_dot[i4].pop()
        else:
            Me_dot[i4]=-1

    # Me_dot 중 마지막 갯수는 필요 없다
    # 처음에는 0 이 온다
    Me_dot=[0]+Me_dot[:-1]
    print('#%i'%t,*Me_dot)

문제 해설 1

마스터의 현재 줄까지 괄호 갯수를 처리해도 들여쓰기는 다음 줄에 적용되므로 한 번에 적용할 수 없다.

현재 줄까지의 괄호 갯수를 다음 줄의 들여쓰기한 . 개수와 비교해야 한다.

그래서 쉽게 비교할 수 있도록 첫 들여쓰기가 괄호 갯수가 없는 것이므로 0, 0, 0 을 초기값에 넣어준다.

# Master . 갯수, (){}[] 갯수
    a=b=c=0
    Master_dot=[]
    Master_bracket=[[0,0,0]]
    for i1 in Master:
        Master_dot.append(len(i1)-len(i1.lstrip('.')))
        for j1 in i1:
            if j1=='(':a+=1
            if j1==')':a-=1
            if j1=='{':b+=1
            if j1=='}':b-=1
            if j1=='[':c+=1
            if j1==']':c-=1
        Master_bracket.append([a,b,c])

문제 해설 2

가능한 R, C, S 를 구해야 한다.

가지고 있는 조건을 가지고 여러가지 공식을 대입하여 구할 수도 있으나 (ex 크래머 공식 등)

너무 복잡하고

가능한 R, C, S 가 각각 1 ~ 20 까지 총 8000 개 이므로

브루트포스로 해결하기로 한다

from itertools import product

# R,C,S 가능성 있는 것들
    candidate=[]

    # 가능한 모든 R,C,S
    for i2 in product(range(1,21), repeat=3):
        R1,C1,S1=i2
        for j2 in range(1,p):
            a1,b1,c1=Master_bracket[j2]
            if R1*a1+C1*b1+S1*c1!=Master_dot[j2]:
                break
        else:
            candidate.append([R1,C1,S1])
for R1 in range(1,21):
    for C1 in range(1,21):
        for S1 in range(1,21):
            # 이렇게 해도 가능하다

문제 해설 3

가능한 R, C, S 를 알고 있으니

"내"가 쓴 글에서 괄호 갯수를 파악해야 한다.

    # Me (){}[] 갯수
    d=e=f=0
    Me_bracket=[]
    for i3 in Me:
        for j3 in i3:
            if j3=='(':d+=1
            if j3==')':d-=1
            if j3=='{':e+=1
            if j3=='}':e-=1
            if j3=='[':f+=1
            if j3==']':f-=1
        Me_bracket.append([d,e,f])

문제 해설 4

가능한 R, C, S 를 가지고 얼마나 들여쓰기 해야하는지 계산해보자

값이 유일하면 그대로 저장하고 유일하지 않다면 -1 을 저장한다

    # 가능성 있는 것들에 대해서 나올 수 있는 점들
    Me_dot=[set() for _ in'a'*q]
    for i4 in range(q):
        d1,e1,f1=Me_bracket[i4]

        for j4 in candidate:
            R2,C2,S2=j4
            Me_dot[i4].add(R2*d1+C2*e1+S2*f1)
        if candidate==[]:
            Me_dot[i4]=-1
        elif len(Me_dot[i4])==1:
            Me_dot[i4]=Me_dot[i4].pop()
        else:
            Me_dot[i4]=-1

문제 해설 5

마무리를 짓는다

첫 문장은 들여쓰기를 하지 않고 마지막 들여쓰기는 필요없으므로 이를 각각 처리한다

    # Me_dot 중 마지막 갯수는 필요 없다
    # 처음에는 0 이 온다
    Me_dot=[0]+Me_dot[:-1]
    print('#%i'%t,*Me_dot)

후기

머리를 써서 쉽게 구하려 하니 자꾸 반례가 생겨서 힘들었다.

상황이 복잡하다면 브루트 포스를 활용하는 것도 문제를 해결 할 때 좋은 것 같다.

아직 알고리즘 공부가 어렵다.