알고리즘/백준 문제풀이

[삼성SW역량][Python/BOJ] 백준 17822 원판돌리기(구현)

개발자 덕구🐾 2022. 8. 2. 21:20
728x90

 

덱으로 이차원 리스트를 만들 수 있다는 것을 처음 알았다..!!

아직도 배울 것이 많다ㅎㅎ

 

이 문제를 푸는 방법은 그저-! 

 

빡구현!!

할수있다!! 화이팅🔥🔥

 

 

1. 숫자들을 리스트 -> 덱으로 만들어 저장한다. 

2. 덱으로 저장되어있으므로 rotate를 이용할 수 있다. 

 

3-1. 양옆을 확인하여 동일한 값이 있는지 체크한다.

3-2. 위, 아래를 확인하여 동일한 값이 있는지 체크한다.

 

4-1. 동일한 값이 있으면 0을 넣는다. 

4-2. 없다면 원판을 돌면서 평균을 구하고 원판을 돌면서 원판위 값을 조정한다. 

 

 

 

 

코드 : 

 

from collections import deque

if __name__=="__main__" :
    n,m,t = map(int,input().split())
    mp = [deque(list(map(int,input().split()))) for _ in range(n)]
    
    for _ in range(t) :
        x,d,k = map(int,input().split())
        
        
        # 0이 아닌 수들의 합 
        result = 0 
        # 회전 
        for i in range(n) :
            result += sum(mp[i])
            if (i+1)%x == 0:
                if d == 0 :
                    mp[i].rotate(k)
                elif d== 1 :
                    mp[i].rotate(-k)
          
        
        if result != 0 :          
            
            have_to_remove = []
            # 같은 반지름의 원반 끼리 비교
            for i in range(n) :
                for j in range(m-1) :
                    if mp[i][j] != 0 and mp[i][j] == mp[i][j+1]:
                        have_to_remove.append((i,j))
                        have_to_remove.append((i,j+1))
                # 맨 처음과 끝 비교 
                if mp[i][0] != 0 and mp[i][0] == mp[i][-1] : 
                    have_to_remove.append((i,0))
                    have_to_remove.append((i,m-1))
                    
            # 반지름이 다른 원끼리 비교 
            for j in range(m) :
                for i in range(n-1) :
                    if mp[i][j] != 0 and mp[i][j] == mp[i+1][j]:
                        have_to_remove.append((i,j))
                        have_to_remove.append((i+1,j))
            
            # 중복 제거 
            have_to_remove = list(set(have_to_remove))
            
            for i in range(len(have_to_remove)) :
                x,y = have_to_remove[i]
                mp[x][y] = 0
                
            # 제거할 숫자가 없다면 
            if len(have_to_remove) == 0 :
                avg_sum = 0
                zero_cnt = 0
                for i in range(n) :
                    avg_sum += sum(mp[i])
                    zero_cnt += mp[i].count(0)
                avg = avg_sum / (n*m-zero_cnt)
                
                for i in range(n) :
                    for j in range(m) :
                        if mp[i][j] != 0 :
                            if mp[i][j] > avg :
                                mp[i][j]-=1 
                            elif mp[i][j] < avg :
                                mp[i][j] +=1 
        # 전부 다 0 일때 
        else : 
            print(0)
            exit(0)
    ans = 0
    for i in range(n) :
        ans += sum(mp[i])
    print(ans)

 

 

 

 


 

 

 

고려해야 할 점들 

 

 

1.

풀이에서 같은 것들이 발견될 때 바로 0을 바꾸는 것이아니라 리스트에 저장해놓았다가

추후에 set으로 중복을 처리한 후 0으로 만든다. 

처음에는 이게 의미가 없다고 생각하여 바로 바로 0으로 만들도록 코드를 만들었었는데 틀렸다.

2개씩만 짝을  짓는 것이 아니라 3개 그리고 그 이상도 동일할 때 함께 0이 될 수 있기 때문이다. 

그래서 같은 것들이 발견되면 함께 have_to_remove라는 리스트에 넣는다. 

 

 

 

 

 

 

그리고 set()을 통해 중복을 제거할 때는[]안에 []가 있으면 에러가 발생한다. 

튜플형태만 set을 통과시켜 중복을 제거할 수 있다.

 

                # 맨 처음과 끝 비교 
                if mp[i][0] != 0 and mp[i][0] == mp[i][-1] : 
                    have_to_remove.append((i,0))
                    have_to_remove.append((i,m-1))

have_to_remove.append([i,0]) 이렇게 하면 set를 적용시키지 못한다. 

 

 

 

 

 

2. 

그리고 반지름이 다른 원끼리 인접한 사이에 값이 같은 지 비교할 때 

for j in range(m) : 

    for i in range(n-1) : 

으로 문제를 해결한 점이 감명깊었다. 

 

 

 

3. 

result를 구하지 않아도 문제가 풀릴것같아서 안구하고 풀어봤는데 아니다.

result가 없으면 틀린다. 

이유는 (m*n)-zero_cnt로 나누기 때문이다. 

result가 0일 때는 zero_cnt가 m*n이 되기때문에 나누는 분모가 0이 되므로 zerodivision 오류가 발생한다. 

 

 

 

 

4. 

그리고 mp[i][j]!=0 and   를 조건에 넣는거 기억하자 ! 

0이되어 사라진 값은 신경쓰지 않기 때문이다. 

 

 

 

 

 

 


 

 

 

 

 

 

복습하면서 만든 약간 더 비효율적인(?) 코드 : < delete 값을 처음부터 set으로 만들었다.> 

from collections import deque


if __name__=="__main__" :
    n,m,t = map(int,input().split())
    mp = []
    for i in range(n) :
        mp.append(deque(list(map(int,input().split()))))
    for _ in range(t) :
        result = 0 
        x,d,k = map(int,input().split())
        for i in range(n) :
            result += sum(mp[i])
            if (i+1) % x == 0:
                if d == 0 :
                    mp[i].rotate(k)
                else :
                    mp[i].rotate(-k)
                    
        if result > 0 :         
            delete = set()
            for i in range(n) :
                for j in range(m-1) :
                    if mp[i][j]!=0 and mp[i][j] == mp[i][j+1] :
                        delete.add((i,j))
                        delete.add((i,j+1))
                if mp[i][0]!=0 and mp[i][0] == mp[i][m-1] :
                    delete.add((i,0))
                    delete.add((i,m-1))
            for j in range(m) :
                for i in range(n-1) :
                    if mp[i][j]!=0 and mp[i][j] == mp[i+1][j] :
                        delete.add((i,j))
                        delete.add((i+1,j))
            
            if len(delete) > 0 :
                for x,y in delete :
                    mp[x][y] = 0
            else :
                zero_cnt = 0
                max_v = 0
                for i in range(n) :
                    for j in range(m) :
                        if mp[i][j] == 0 :
                            zero_cnt +=1 
                        else :
                            max_v += mp[i][j]
                avg_v = max_v / ((m*n)-zero_cnt)
                for i in range(n) :
                    for j in range(m) :
                        if mp[i][j]!=0 and mp[i][j]> avg_v : mp[i][j] -=1 
                        elif mp[i][j]!=0 and mp[i][j] < avg_v : mp[i][j] +=1 
        else :
            print(0)
            exit(0)
    
    ans = 0
    for i in range(n) :
        ans += sum(mp[i])
    print(ans)

 

 

 

 

 

 

 

참고 블로그 : 

https://hoyeonkim795.github.io/posts/17822/

 

[백준] #17822 원판돌리기 Python (파이썬)

원판돌리기

hoyeonkim795.github.io

 

 

복습 :

✔ 20220911

 

반응형