[백준 15685번] 드래곤 커브 - Python으로 구현하기

 

문제 접근

  • 규칙성을 찾아봐야 하는 문제

* 드래곤 커브의 규칙은 다음과 같다.

방향이 0 인 드래곤 커브의 세대별 방향 정보 규칙

0세대 : 0

1세대 : 0 1

2세대 : 0 1 2 1

3세대 : 0 1 2 1 2 3 2 1

4세대 : 0 1 2 1 2 3 2 1 2 3 0 3 2 3 2 1

...

그 전 세대의 reverse로 +1 씩 증가하는 형태이다.

 

 

 

생각해볼 점

  • 규칙없이 풀 수 있을까? 단순 구현으로!

 

오답 분석

  • x,y 좌표가 행렬의 row,col과 반대로 주어져 그림이 잘못 그려질 수 있다. 주의!

 

N = int(input())
map_data = [[1]*101 for _ in range(101)]
di = {0:[0,1],1:[-1,0],2:[0,-1],3:[1,0]}
for _ in range(N):
    x,y,d,g,=map(int,input().split())

    curve_info=[d]
    for _ in range(g):
        curve_info += [(i+1)%4 for i in curve_info[::-1]]
    map_data[y][x]=0
    nx=x
    ny=y
    print(curve_info)
    for curve in curve_info:
        nx=nx+di[curve][1]
        ny=ny+di[curve][0]
        map_data[ny][nx]=0

for i in map_data:
    print(i)

# 정답 구하기
cnt=0
for i in range(100):
    for j in range(100):
        if map_data[i][j]+map_data[i][j+1]+map_data[i+1][j]+map_data[i+1][j+1]==0:
            cnt+=1
print(cnt)

 

* 틀린 부분이나 더 나은 방법이 있을 수 있습니다. 지적해주시면 감사하겠습니다!!

[백준 15686번] 치킨 배달 - Python으로 구현하기

 

문제 접근

  • O(13Cm*N*N)의 시간복잡도로 구할 수 있다.
  • 집의 좌표, 치킨집의 좌표를 모두 저장해 둔 뒤, 주어진 공식대로 최단거리를 찾으면 된다

 

생각해볼 점

  • 시간복잡도를 고려하지않고 BFS로 접근했다가 실패했다. 시간복잡도를 꼭 고려하기!

 

오답 분석

  • 최단 거리 구할 때 시간초과 조심

 

from itertools import combinations as cm
import math

N,M = map(int,input().split())
map_data = [list(map(int,input().split())) for _ in range(N)]
chi = []
home = []
for i in range(N):
    for j in range(N):
        if map_data[i][j]==2:
            map_data[i][j]=0
            chi.append([i,j])
        elif map_data[i][j]==1:
            home.append([i,j])
ans=math.inf
for now_chi in cm(chi,M):
    now_sum=0
    for h in home:
        dist=math.inf
        for k in now_chi:
            dist=min(dist,abs(h[0]-k[0])+abs(h[1]-k[1]))
        now_sum+=dist
    ans=min(ans,now_sum)
print(ans)

 

* 틀린 부분이나 더 나은 방법이 있을 수 있습니다. 지적해주시면 감사하겠습니다!!

[백준 16234번] 인구 이동 - Python으로 구현하기

 

문제 접근

  • BFS로 주어진 조건과 연결된 노드들을 숫자로 표시해주자
  • 노드들을 연결하면서 합과 개수를 구해 딕셔너리에 보관하자
  • 행렬을 돌면서 자신의 union에 맞는 합과, 개수를 나누어 갱신해주자

 

생각해볼 점

  • 종료조건이 괜찮은지?

 

오답 분석

  • 연합개수*N*N 으로 구하지 않도록 주의, 메모리를 사용하자!

 

from collections import deque

def find_union(start,num):
    dq = deque()
    dq.append(start)
    union[start[0]][start[1]]=num
    union_sum=A[start[0]][start[1]]
    union_cnt=1
    while dq:
        x,y=dq.popleft()
        for k in range(4):
            nx=x+di[k][0]
            ny=y+di[k][1]

            if 0<=nx<N and 0<=ny<N and union[nx][ny]==-1 and L<=abs(A[x][y]-A[nx][ny])<=R:
                union_sum+=A[nx][ny]
                union[nx][ny]=num
                union_cnt+=1
                dq.append([nx,ny])
    return [union_sum,union_cnt]

N,L,R=map(int,input().split())
A = [list(map(int,input().split())) for _ in range(N)]

di = [[-1,0],[0,-1],[1,0],[0,1]]
cnt=0
while True:
    union = [[-1] * N for _ in range(N)]
    n=0
    union_info={}
    for i in range(N):
        for j in range(N):
            if union[i][j]==-1:
                union_info[n]=find_union([i,j],n)
                n+=1

    if n==N*N:    # 모든 국경선이 열리지 않음
        break

    # 국경 업데이트
    for i in range(N):
        for j in range(N):
            A[i][j]=union_info[union[i][j]][0]//union_info[union[i][j]][1]
    cnt+=1
print(cnt)

 

* 틀린 부분이나 더 나은 방법이 있을 수 있습니다. 지적해주시면 감사하겠습니다!!

[백준 16235번] 나무 재테크 - Python으로 구현하기

 

문제 접근

  • 봄,여름,가을,겨울 주어진 조건대로 구현하기
  • 나무의 나이를 리스트로 만들어 2D에 저장 하여 구현하자

 

생각해볼 점

  • 가을에 나무가 확산 될 때 리스트의 앞에 넣으면 정렬을 반복 할 필요가 없을 것 같다.

 

오답 분석

  • 여름에서 나무의 나무를 증가시키고 양분을 제거하는 실수를 범했다. 찾기 엄청 힘들었다..
  •  

 

N,M,K=map(int,input().split())  # n:n*n, m개 나무 k년
A = [list(map(int,input().split())) for _ in range(N)]
tree = [[[] for _ in range(N)] for _ in range(N)]

for _ in range(M):
    x,y,z=map(int,input().split())
    tree[x-1][y-1].append(z)

ground = [[5]*N for _ in range(N)]

for _ in range(K):
    # 봄
    for i in range(N):
        for j in range(N):
            if len(tree[i][j])<=0: continue
            tree[i][j].sort()
            idx=0
            while idx<len(tree[i][j]):
                if tree[i][j][idx]<=ground[i][j]:
                    ground[i][j]-=tree[i][j][idx]
                    tree[i][j][idx] += 1
                    idx+=1
                else:
                    die = tree[i][j][idx:]
                    for now in die:    # 죽은나무!
                        ground[i][j]+=(now//2)
                    tree[i][j]=tree[i][j][:idx]
                    break

    # 가을
    di = [[-1,0],[0,-1],[1,0],[0,1],[1,1],[1,-1],[-1,1],[-1,-1]]
    for i in range(N):
        for j in range(N):
            c=0
            if tree[i][j]:
                for now in tree[i][j]:
                    if now%5==0:
                        c+=1
            if c>0:
                for k in range(8):
                    ni=i+di[k][0]
                    nj=j+di[k][1]
                    if 0<=ni<N and 0<=nj<N:
                        for _ in range(c):
                            tree[ni][nj].append(1)

    # 겨울
    for i in range(N):
        for j in range(N):
            ground[i][j]+=A[i][j]

ans=0
for i in range(N):
    for j in range(N):
        ans+=len(tree[i][j])
print(ans)

 

* 틀린 부분이나 더 나은 방법이 있을 수 있습니다. 지적해주시면 감사하겠습니다!!

[백준 16236번] 아기 상어 - Python으로 구현하기

 

문제 접근

  • 정해진 규칙에 따라 아기 상어의 다음 위치를 정해주어야 한다.
  • 거리가 같은 먹을 수 있는 곳이 여러 개인 경우 가장 높고, 가장 왼쪽에 있는 좌표로 이동한다.

 

생각해볼 점

  • 짜다보니 하드코딩을 해버렸다. baby shark의 정보들을 깔끔하게 관리하고, 로직도 다시 생각해봐야 겠다.

 

오답 분석

  • 거리가 같은 상어들의 우선순위를 정해주지 않으면 오답!

 

def find_shark(baby):
    global map_data,baby_pos,baby_size,baby_eat_cnt,time

    dq = deque()
    dq.append(baby)
    dist = [[-1] * N for _ in range(N)]
    dist[baby[0]][baby[1]]=0
    min_dist=N*N

    while dq:
        x,y=dq.popleft()

        for k in range(4):
            nx = x+di[k][0]
            ny = y+di[k][1]

            if 0<=nx<N and 0<=ny<N and dist[nx][ny]==-1 and map_data[nx][ny]<=baby_size:
                dist[nx][ny]=dist[x][y]+1
                dq.append([nx,ny])
                if 0<map_data[nx][ny]<baby_size:
                    min_dist=min(min_dist,dist[nx][ny])

    next_pos=[]
    for i in range(N):
        for j in range(N):
            if dist[i][j]==min_dist and 0<map_data[i][j]<baby_size:
                next_pos.append([i,j])

    if next_pos:
        next_pos.sort(key=lambda x:(x[0],x[1]))
        baby_pos=next_pos[0]
        baby_eat_cnt+=1
        time += min_dist
        map_data[baby_pos[0]][baby_pos[1]]=0
        return True
    else:
        return False


from collections import deque

N = int(input())
map_data = [list(map(int,input().split())) for _ in range(N)]

baby_size = 2
baby_pos = [0,0]
baby_eat_cnt = 0
di = [[-1,0],[0,-1],[0,1],[1,0]]

for i in range(N):
    for j in range(N):
        if map_data[i][j]==9:
            baby_pos=[i,j]
            map_data[i][j]=0
            break

time = 0
while True:
    if not find_shark(baby_pos):
        break
    if baby_eat_cnt==baby_size:
        baby_eat_cnt=0
        baby_size+=1
print(time)

 

* 틀린 부분이나 더 나은 방법이 있을 수 있습니다. 지적해주시면 감사하겠습니다!!

[백준 17144번] 미세먼지 안녕! - Python으로 구현하기

 

문제 접근

  • 주어진 순서대로 확산 -> 순환 과정을 구현하면 된다.
  • 확산 과정 : 임의 tmp 배열에 확산된 값을 저장하고(동시에 확산하기 때문에) 확산이 끝나면 기존 미세먼지값에 업데이트 해준다. 또한, 주어진 수식에 따라 확산양*확산된 곳 개수 을 빼준다.
  • 순환 과정 : 배열의 테두리를 돌려야한다. 임의 tmp 배열 하나를 생성해두어 간단하게 처리 가능하다.(모서리부분 주의)

 

생각해볼 점

  • 배열 테두리를 돌리는데 더 나은 방법?

 

R,C,T=map(int,input().split())
A = [list(map(int,input().split())) for _ in range(R)]
di = [[-1,0],[0,-1],[1,0],[0,1]]
time = 0
while time<T:
    # 미세먼지 확산
    tmp_A = [[0] * C for _ in range(R)]
    for i in range(R):
        for j in range(C):
            if A[i][j]>0:
                cnt = 0
                for k in range(4):
                    ni=i+di[k][0]
                    nj=j+di[k][1]
                    if 0<=ni<R and 0<=nj<C and A[ni][nj]!=-1:
                        tmp_A[ni][nj]+=(A[i][j]//5)
                        cnt+=1
                A[i][j]=A[i][j]-(A[i][j]//5)*cnt

    # 기존 A와 확산 미세먼지 합치기
    for i in range(R):
        for j in range(C):
            A[i][j]+=tmp_A[i][j]

    # 공기청정기 순환
    tmp_A = [[-2] * C for _ in range(R)]
    up_machine_row=0
    for row in range(R):
        if A[row][0]==-1:
            up_machine_row=row
            break
    # 위쪽
    for i in range(1,C):
        tmp_A[0][i-1]=A[0][i]
        tmp_A[up_machine_row][i]=A[up_machine_row][i-1]
        tmp_A[up_machine_row][1]=0
    for i in range(1,up_machine_row+1):
        if A[i][0]!=-1:
            tmp_A[i][0]=A[i-1][0]
        tmp_A[i-1][C-1]=A[i][C-1]


    # 아래쪽
    for i in range(1,C):
        tmp_A[R-1][i-1]=A[R-1][i]
        tmp_A[up_machine_row+1][i]=A[up_machine_row+1][i-1]
        tmp_A[up_machine_row+1][1]=0
    for i in range(up_machine_row+2,R):
        if A[i-1][0]!=-1:
            tmp_A[i-1][0]=A[i][0]
        tmp_A[i][C-1]=A[i-1][C-1]

    for i in range(R):
        for j in range(C):
            if tmp_A[i][j]!=-2:
                A[i][j]=tmp_A[i][j]
    time+=1

print(sum(list(sum(A,[])))+2)

 

* 틀린 부분이나 더 나은 방법이 있을 수 있습니다. 지적해주시면 감사하겠습니다!!

[백준 17143번] 낚시왕 - Python으로 구현하기

 

문제 접근

  • 주어진 문제대로 구현하는 구현 문제.
  • 상어가 속력만큼 움직이는 것을 구현해야 하는데, 아래 규칙을 보면 반복문 횟수를 줄일 수 있다.
  • [0] ~ [k] ~ [n-1] : k에 있는 상어가 n-1으로 갔다가 회전하여 0을 찍고 다시 k로 돌아오는건 (n-1-k) + (n-1) + (k) = 2*n-2이다. 따라서 상어가 움직일 수 있는 범위는 속력%(2*n-2)
  • 아직 안움직인 상어를 잡어먹을 순 없으므로 새로운 2D 배열로 움직인 상어들을 저장, 비교

 

생각해볼 점

  • 상어의 움직이는 처리를 좀더 깔끔하게 할 수 없을지?
  • 하드 코딩으로 풀었는데, 다른 로직이 없는지 생각해보기

 

오답 분석

  • 시간 초과가 많이 나는 문제로, 주어진 반복문을 최적화 할 수 있어야한다.

 

def catch_shark():
    global catch_cnt
    for row in range(R):
        if map_data[row][person]:
            catch_cnt+=map_data[row][person][2]
            map_data[row][person]=[]
            return

def shark_move():
    global map_data
    tmp_shark = [[[] for _ in range(C)] for _ in range(R)]
    for i in range(R):
        for j in range(C):
            if map_data[i][j]:
                direction = map_data[i][j][1]
                ni=i
                nj=j
                if 1<=direction<=2: # 세로방향
                    for _ in range(map_data[i][j][0]%(2*len(map_data)-2)):
                        ni=ni+di.get(direction)[0]
                        nj=nj+di.get(direction)[1]
                        if ni==-1 or ni == len(map_data):    # 끝까지 간 경우 방향전환
                            direction= 2 if direction==1 else 1
                            ni = ni + di.get(direction)[0]
                            ni = ni + di.get(direction)[0]
                            map_data[i][j][1]=direction

                elif 3<=direction<=4: # 가로방향
                    for _ in range(map_data[i][j][0]%(2*len(map_data[0])-2)):
                        ni=ni+di.get(direction)[0]
                        nj=nj+di.get(direction)[1]
                        if nj==-1 or nj == len(map_data[0]):
                            direction = 4 if direction == 3 else 3
                            nj = nj + di.get(direction)[1]
                            nj = nj + di.get(direction)[1]
                            map_data[i][j][1] = direction

                if tmp_shark[ni][nj]:   # 이미 상어가 있는 경우
                    if tmp_shark[ni][nj][2]<map_data[i][j][2]:
                        tmp_shark[ni][nj] = map_data[i][j]
                else:
                    tmp_shark[ni][nj] = map_data[i][j]
    map_data=tmp_shark


R,C,M = map(int,input().split())
map_data = [[[] for _ in range(C)] for _ in range(R)]
di = {1:[-1,0],2:[1,0],3:[0,1],4:[0,-1]}

for _ in range(M):
    r,c,s,d,z = map(int,input().split())
    map_data[r-1][c-1]=[s,d,z]

person=-1
catch_cnt=0
while person<C-1:
    person+=1   # 사람을 오른쪽 열로 이동
    catch_shark()
    shark_move()
print(catch_cnt)

 

* 틀린 부분이나 더 나은 방법이 있을 수 있습니다. 지적해주시면 감사하겠습니다!!

[백준 17140번] 이차원 배열과 연산 - Python으로 구현하기

 

문제 접근

  • 행과 열에 대한 연산을 구현해야 되는 경우에는 행에 대한 연산 구현 후 transpose 하여 열도 처리한다.
  • 주어진 조건이 많으므로 차근차근히 구현해야한다.
  • 행의 정수 빈도 수는 collections 모듈의 Counter를 사용하자.

 

생각해볼 점

  • transpose하지 않고 구하기

 

오답 분석

  • Counting 할때 0을 제거하지 않으면 오답!
  • 100개까지만 취급하는 조건 주의
  • time이 100인 경우에도 확인 해야한다.

 

from collections import Counter

r,c,k=map(int,input().split())
A = [list(map(int,input().split())) for _ in range(3)]

r-=1	# 0 index
c-=1
time=0	# 시간
while time<=100:
    if r<len(A) and c<len(A[0]) and A[r][c]==k:	# 정답 확인
        print(time)
        break

    # C연산인 경우 : transpose
    C_flag=False
    if len(A)<len(A[0]):
        C_flag=True
        A=list(zip(*A))

    # row에 대한 주어진 연산 구현
    max_len=0
    tmp_a = []
    for now_row in A:
        ct = Counter(now_row)
        if ct.get(0):	# 0은 카운팅하지 않음!
            del ct[0]
        num_cnt = list(map(list,ct.items()))
        num_cnt.sort(key=lambda x :(x[1],x[0]))		# 주어진 순서대로 정렬
        tmp_a.append(list(sum(num_cnt,[]))[:100])	# 100개를 초과하는 경우 100개 까지만
        max_len=max(max_len,len(tmp_a[-1]))

    for i in range(len(tmp_a)):
        if len(tmp_a[i])<max_len:
            tmp_a[i]+=[0]*(max_len-len(tmp_a[i]))	# 길이 맞춰주기

    A=tmp_a

    if C_flag:		# C연산 인경우 다시 transpose
        A=list(zip(*A))
    time+=1

if time>100:
    print(-1)

 

* 틀린 부분이나 더 나은 방법이 있을 수 있습니다. 지적해주시면 감사하겠습니다!!

[백준 17142번] 연구소 3 - Python으로 구현하기

 

문제 접근

  • BFS 문제이고, 역시나 itertools의 combinations로 조합의 수를 구해보자
  • 단, 문제에서 구해야 되는 건 그냥 dist가 아닌, 활성화바이러스가 아닌 칸의 dist 최대값으로 구해줘야한다.
  • 따라서 if map_data[nx][ny]==0: 의 조건안에 최대 dist를 구하는 부분으로 해결

 

생각해볼 점

  • list(sum(ar,[])) 대신 itertools의 chain 모듈을 쓰는게 훨씬 빠르다. Chain(*ar)

 

오답 분석

  • 비활성화 -> 활성화 되는 바이러스의 dist를 고려하는 실수가 많다.

 

from collections import deque
from itertools import combinations as cm

def bfs(virus_list):
    dist = [[-1] * N for _ in range(N)]
    dq=deque()
    for pos in virus_list:
        dq.append(pos)
        dist[pos[0]][pos[1]] = 0
    max_dist=0
    while dq:
        x,y=dq.popleft()
        for k in range(4):
            nx=x+di[k][0]
            ny=y+di[k][1]

            if 0<=nx<N and 0<=ny<N and map_data[nx][ny]!=1 and dist[nx][ny]==-1:
                dist[nx][ny]=dist[x][y]+1
                if map_data[nx][ny]==0:
                    max_dist=max(max_dist,dist[nx][ny])
                dq.append([nx,ny])

    a = list(sum(dist,[]))
    if a.count(-1)==list(sum(map_data,[])).count(1):	# 방문 안 한 곳이 벽의 개수와 동일한지
        ans.append(max_dist)	# 리스트없이 바로 min값 구해도 됨

N,M = map(int,input().split())
map_data = [list(map(int,input().split())) for _ in range(N)]
di = [[1,0],[0,1],[-1,0],[0,-1]]

virus_pos=deque()
ans=[]
for i in range(N):
    for j in range(N):
        if map_data[i][j]==2:
            virus_pos.append([i,j])

for now_virus_list in cm(virus_pos,M):
    bfs(now_virus_list)

print(min(ans) if ans else -1)

 

* 틀린 부분이나 더 나은 방법이 있을 수 있습니다. 지적해주시면 감사하겠습니다!!

[백준 15684번] 사다리 조작 - Python으로 구현하기

 

문제 접근

  • 주어진 사다리를 자료구조로 어떻게 표현해야 될지? 어떤 규칙이 있는지? 하나의 라인을 따라가보며 확인
  • 내가 생각한 사다리 자료구조는 배열이다.
  • itertools 의 product로 모든 인덱스 경우의 수를 구하고, combinations 로 조합을 뽑은 뒤 완전탐색을 해보자

[사다리 자료구조]

위 예시 사다리를 행렬로 표현해보면, 아래와 같다.(행은 가로선을 놓을 수 있는 곳, 열은 출발 라인번호)

  1 2 3 4
1 1 0 0 0
2 0 0 1 0
3 0 1 0 0
4 0 0 0 0
5 1 0 0 1
6 0 0 0 0

 

array[1][1]은 1번->2번 가로선이 1번 가로선 놓을수 있는 곳에 위치해 있음을 뜻한다.

반복문으로 각 열마다 어떤 위치로 가는지 확인하여 i열이 i열로 끝나지 않으면 continue 하고, 다음 경우의수를 확인한다.

어떤 위치로 가는지 확인 하는 구체적인 방법은 아래 코드에서 확인!

 

생각해볼 점

  • 사다리 타기에 대한 로직을 한번 생각해 볼 수 있는 문제
  • product 모듈 안쓰고 인덱스 모든 경우의 수 찾기?(modular로 가능)
  • 최적화 고려해보기.

 

오답 분석

  • 시간초과가 많이 나는 문제이다.
  • 내 실수 : 반복문 안에 copy 모듈을 사용하여 처리를 깔끔하게 하려고 했으나, deepcopy의 시간복잡도가 O(n^2) 인것을 간과했다. 주의!!

 

* 2019-10-18 기준 백준 pypy3 채점서버에서 exit(0)을 런타임 에러로 인식하는 오류 있음.

from itertools import product,combinations as cm

def chk_sadari(sa,sa_added):
    for col in range(1,n+1):
        go = col
        for row in range(1,h+1):
            if sa[row][go]==1 or sa_added[row][go]==1:
                go+=1
            elif sa[row][go-1]==1 or sa_added[row][go-1]==1:
                go-=1
        if go != col:
            return False
    return True

n,m,h=map(int,input().split())
sadari = [[0]*(n+1) for _ in range(h+1)]    # 1 index

# 가로선이 없는 경우 예외처리
if m==0:
    print(0)
    exit(1)

# 사다리 입력정보
for _ in range(m):
    a,b=map(int,input().split())
    sadari[a][b]=1

if chk_sadari(sadari,sadari):
    print(0)
    exit(1)

for i in range(1,3+1):
    for now_line_list in cm(product(range(1,h+1),range(1,n)),i):  # 행렬의 인덱스를 1~h개를 뽑는 조합
        sadari_added = [[0]*(n+1) for _ in range(h+1)]
        # 뽑은 조합들로 사다리에 가로선 추가하기
        flag = False
        for pos in now_line_list:
            x,y=pos
            if sadari[x][y-1]==1 or sadari_added[x][y-1]==1 or sadari[x][y+1]==1 or sadari_added[x][y+1]==1 or sadari[x][y]==1:
                flag=False
                break
            sadari_added[x][y]=1
            flag= True
        if flag and chk_sadari(sadari,sadari_added):
            print(i)
            exit(1)
print(-1)

 

* 틀린 부분이나 더 나은 방법이 있을 수 있습니다. 지적해주시면 감사하겠습니다!!

[백준 14891번] 톱니바퀴 - Python으로 구현하기

 

문제 접근

  • 주어진 문제는 구현 문제로 처음에 너무 어려워보였다. 쫄지말고 차근차근 접근하는 것이 필요.
  • 우선 톱니바퀴를 자료형으로 어떻게 표현 할 것인지, 주어진 조건에 따라 돌리는 경우, 안돌리는 경우를 어떻게 구현 할 것인지 부터 접근하자.
  • 톱니바퀴의 표현 : deque(index는 12시방향부터 시계방향으로 0~7을 가진다.)
  • 회전하는 경우 : 주어진 시작 톱니를 회전하고 왼쪽방향, 오른쪽방향 나누어서 돌린다. 도중에 맞닿은 부분이 같은 극인 경우 반복문 탈출
  • 참고 : 원형 돌리기 문제는 deque의 rotate 메소드를 쓰면 편하게 구현가능하다.

생각해볼 점

  • deque 와 list의 상황 별 시간복잡도가 어떻게 되는지 다시 한번 정리 필요
  • 재귀로 도전?

 

오답 분석

  • 1번, 4번 톱니가 시작인 경우 인덱스 처리를 잘못해주어 오류가 난 경우가 많아 보인다. 주의!

 

from collections import deque

circle = [deque(map(int,input())) for _ in range(4)]
opers = deque(list(map(int,input().split())) for _ in range(int(input())))

while opers:	# 명령어가 남아 있으면 반복문 실행
    num,direct = opers.popleft()
    num-=1  # 0 index
    tmp_2 = circle[num][2]	# 비교 대상 백업
    tmp_6 = circle[num][6]	# 비교 대상 백업
    circle[num].rotate(direct)	# 일단 시작 톱니 돌려주기
    tmp_direct=direct
    
    # 시작 톱니 왼쪽 방향
    direct=tmp_direct
    for i in range(num-1,0-1,-1):
        if circle[i][2]!=tmp_6:		# 서로 다른 극인 경우
            tmp_6=circle[i][6]
            circle[i].rotate(direct*-1)
            direct*=-1
        else:
            break

    # 시작 톱니 오른쪽 방향
    direct=tmp_direct
    for i in range(num+1,4):
        if circle[i][6]!=tmp_2:		# 서로 다른 극인 경우
            tmp_2 = circle[i][2]
            circle[i].rotate(direct*-1)
            direct*=-1
        else:
            break

ans=0
for i in range(4):
    if circle[i][0]==1:
        ans += (2**i)
print(ans)

 

* 틀린 부분이나 더 나은 방법이 있을 수 있습니다. 지적해주시면 감사하겠습니다!!

[백준 14890번] 경사로 - Python으로 구현하기

 

문제 접근

  • 경사로를 놓을 수 있는 방법 : 높은 곳 -> 낮은 곳  / 낮은 곳 -> 높은 곳
  • 경사로가 겹치면 안되므로 경사로가 놓여진 부분은 따로 체크해주기
  • 2d에서 행과 열을 모두 확인해봐야 되는 문제이다. 행에 대한 구현만 완료한 뒤 2d 행렬을 트랜스포즈하여 열을 확인하자.
  • Python에서 2D array transpose : t_arr = list(zip(*arr))

 

생각해볼 점

  • [i][j] , [j][i] 의 순서로 이중 반복문 하나로 한번에 처리 가능하다 => 사실 트랜스포즈 과정이 필요없다.

 

 

오답 분석

  • 인덱스 표현에 주의하고 정확하게 하자! 한군데 틀리면 찾기 힘들다.
  • 인덱스를 다루는 문제일 수록 경계값 처리 꼼꼼하게 확인하기

 

def row_solve(arr):
    global cnt
    chk = [[False] * n for _ in range(n)]
    for i in range(n):
        j = 0
        go_flag = True
        while j < n - 1:
            if arr[i][j] == arr[i][j + 1]:
                j += 1
                continue
            elif arr[i][j] - arr[i][j + 1] == 1:  # 높->낮
                if arr[i][j + 1:j+1+L].count(arr[i][j+1]) == L:
                    chk[i][j + 1:j + 1 + L] = [True] * L
                    j = j + L
                    continue
                else:
                    go_flag = False
                    break
            elif arr[i][j] - arr[i][j + 1] == -1:  # 낮->높
                if arr[i][j+1 - L:j+1].count(arr[i][j]) == L and True not in chk[i][j+1 - L:j+1]:
                    chk[i][j+1 - L:j+1] = [True] * L
                    j += 1
                    continue
                else:
                    go_flag = False
                    break
            else:
                go_flag = False
                break

        if go_flag:
            cnt += 1

n,L=map(int,input().split())
map_data = [list(map(int,input().split())) for _ in range(n)]

cnt = 0
row_solve(map_data)
row_solve(list(zip(*map_data)))
print(cnt)

 

* 틀린 부분이나 더 나은 방법이 있을 수 있습니다. 지적해주시면 감사하겠습니다!!

[백준 14889번] 스타트와 링크 - Python으로 구현하기

 

문제 접근

  • 두 팀으로 나누는 경우의 수를 어떻게 구할지?
  • itertools 의 combinations 모듈 사용! n//2 개의 조합을 뽑아서 1팀과 2팀으로 나눔

 

생각해볼 점

  • combinations 모듈 없이 어떻게 구현할지?
from itertools import combinations as cm
import math

n = int(input())
datas = [list(map(int,input().split())) for _ in range(n)]

min_ans=math.inf	# 정답

for case in cm(range(1,n+1),n//2):	# 두 팀으로 나눌 수 있는 경우의 수
    s1 = s2 = 0
    
    for i in case:	# 1팀 점수
        for j in case:
            s1+=datas[i-1][j-1]

    res = set(range(1, n + 1)) - set(case)	# 2팀 점수
    for i in res:
        for j in res:
            s2+=datas[i-1][j-1]
    min_ans=min(min_ans,abs(s1-s2))
print(min_ans)

 

* 틀린 부분이나 더 나은 방법이 있을 수 있습니다. 지적해주시면 감사하겠습니다!!

[백준 14888번] 연산자 끼워넣기 - Python으로 구현하기

 

문제 접근

  • 주어진 연산자 개수내에 적절히 연산자를 조합하여 식 결과의 최댓값, 최솟값 찾기
  • itertools 의 permutations 모듈 사용하여 모든 경우의수 확인
  • set 을 사용하여 중복을 제거하자

 

생각해볼 점

  • 재귀 함수로 구현 가능해보임

 

오답 분석

  • 음수를 나누기 하는 경우 문제에 조건에 주어진 대로 처리

 

from itertools import permutations as pm

n = int(input())
nums = list(map(int,input().split()))
opers = list(map(int,input().split()))

# 입력받은 명령어 저장
op=''
for idx,oper in enumerate(opers):
    op+=str(idx)*oper

op=list(map(int,op))
res_list=[]
for now_op in set(pm(op,len(op))):	# 경우의 수(중복 제거)
    res = nums[0]
    for idx in range(n-1):
        if now_op[idx] == 0:
            res+= nums[idx + 1]
        elif now_op[idx] == 1:
            res-= nums[idx + 1]
        elif now_op[idx] == 2:
            res *=nums[idx + 1]
        elif now_op[idx] == 3:
            res = res//nums[idx + 1] if res>0 else ((res*-1)//nums[idx+1])*-1	# 음수 나누기 조심
    res_list.append(res)

print(max(res_list))
print(min(res_list))

 

* 틀린 부분이나 더 나은 방법이 있을 수 있습니다. 지적해주시면 감사하겠습니다!!

[백준 14503번] 로봇 청소기 - Python으로 구현하기

 

문제 접근

  • 정말 주어진대로 구현해야되는 구현 문제
  • 바라 보는 방향의 왼쪽을 표현하는 것이 관건
  • 입력으로 주어진 방향의 왼쪽방향은 -1 씩 감소되고, 반대편 방향은 2가 차이 난다.(0,1인경우는 예외처리)
  • 왼쪽방향 : n_dir = dir - 1 if dir>0 else 3 / 반대편 방향 : n_dir = dir - 2 if dir>1 else dir + 2

 

생각해볼 점

  • 문제를 코드에 옮기기 전, 대략적으로 구성도를 짜고 작성하기

 

오답 분석

  • 구현하면서 dir과 di가 헷갈리곤 했다. 변수 이름 잘 정해주기!

 

n,m=map(int,input().split())    # 맵 크기
r,c,dir = map(int,input().split())    # 로봇 r,c / 방향(0~3 : 북동남서)
map_data = [list(map(int,input().split())) for _ in range(n)]   # 빈칸0, 벽1
di = {0:[-1,0],1:[0,1],2:[1,0],3:[0,-1]}
while True:
    map_data[r][c] = 2  # 현재 위치 청소
    tmp_dir = dir
    chk_flag=False
    for _ in range(4):
        tmp_dir = dir-1 if dir>0 else 3 # 현재 보고있는 방향의 왼쪽부터 탐색
        nr=r+di[tmp_dir][0]
        nc=c+di[tmp_dir][1]
        if map_data[nr][nc]==0: # 왼쪽 방향에 청소 안한게 존재, 회전 후 한칸 전진

            dir=tmp_dir
            r,c=nr,nc
            chk_flag=True
            break
        else:
            dir=tmp_dir # 왼쪽 방향에 청소공간 없으면 회전

    if chk_flag:    # 왼쪽방향 청소안한게 있으면!
        continue

    tmp_dir = dir-2 if dir>1 else dir+2
    if map_data[r+di[tmp_dir][0]][c+di[tmp_dir][1]]==1:
        break
    else:
        r+=di[tmp_dir][0]
        c+=di[tmp_dir][1]

print(sum(map_data,[]).count(2))

 

* 틀린 부분이나 더 나은 방법이 있을 수 있습니다. 지적해주시면 감사하겠습니다!!

[백준 14502번] 연구소 - Python으로 구현하기

 

문제 접근

  • 바이러스의 확산 => BFS 알고리즘
  • 벽을 세울 수 있는 경우의수 => itertools 모듈의 combinations, product
  • 안전영역 확인 => chain, counter 모듈
  • 메모리 효율성 문제로 제너레이터로 combinations 구현

 

생각해볼 점

  • itertools 모듈 안쓰고 경우의수 어떻게 뽑으면 좋을지?
  • copy 모듈을 이용하여 마지막 원상 복귀 코드 없애기

 

오답 분석

  • 항상 불필요한 로직이 없는지 확인하기

 

# 연구소
import sys
input = lambda:sys.stdin.readline().rstrip()

from itertools import product,chain,combinations as cm
from collections import deque,Counter

n,m=map(int,input().split())
a =[list(map(int,input().split())) for _ in range(n)]   # 맵

dq=deque()
di =[[-1,0],[0,-1],[1,0],[0,1]] # 4방향
max_cnt=0

for wall in cm(list(product(range(n),range(m))),3):
    return_wall=True
    for w in wall:
        x,y=w
        if a[x][y]==1 or a[x][y]==2:    # 벽을 둘 수 없는 자리
            return_wall=False
            break
    if not return_wall: continue    # 벽 3개를 설치 못한 경우
    else:
        for w in wall:  # 벽 설치
            x,y=w
            a[x][y]=1

    # 바이러스들 deque에 삽입
    for i in range(n):
        for j in range(m):
            if a[i][j]==2:
                dq.append([i,j])

    # bfs
    while dq:
        x,y=dq.popleft()
        for k in range(4):
            nx=x+di[k][0]
            ny=y+di[k][1]
            if 0<=nx<n and 0<=ny<m and a[nx][ny]==0:
                dq.append([nx,ny])
                a[nx][ny]=-1

    c=Counter(chain(*a))    # 2차원 맵 -> 1차원 맵
    max_cnt=max(max_cnt,c[0])   # 0의 개수

    # 기존 맵으로 원상복귀
    for w in wall:
        x,y=w
        a[x][y]=0
    for i in range(n):
        for j in range(m):
            if a[i][j]==-1:
                a[i][j]=0
print(max_cnt)

 

* 틀린 부분이나 더 나은 방법이 있을 수 있습니다. 지적해주시면 감사하겠습니다!!

[백준 14501번] 퇴사 - Python으로 구현하기

 

문제 접근

  • DP인지? 브루트포스인지?
  • 입력값의 범위로 봐서 브루트포스로 해결 가능해 보인다.
  • 해당 날짜에 상담을 진행하는 경우, 안하는 경우를 재귀적으로 구현하여 모든 경우를 다 보고 최대값만 뽑자

 

생각해볼 점

  • dp로 어떻게 접근해야할지?

 

오답 분석

  • 재귀 구현의 종료조건, 진행조건에 주의하기!

 

# 퇴사
n = int(input())
T = []
P = []
for _ in range(n):
    t,p=map(int,input().split())
    T.append(t)
    P.append(p)

ans = 0

# 종료 : index 가 n을 넘은 경우
# 진행 : index+t[i]가 n보다 작은 경우

def sol(index, profit):
    global ans

    if index > n:
        return
    if index == n:
        ans = max(ans, profit)
        return
    sol(index + 1, profit)
    sol(index + T[index], profit + P[index])

sol(0, 0)
print(ans)

 

* 틀린 부분이나 더 나은 방법이 있을 수 있습니다. 지적해주시면 감사하겠습니다!!

[백준 14500번] 테트로미노 - Python으로 구현하기

 

문제 접근

  • 테트로미노가 되는 도형 5개를 제시해주었다.
  • 해당 도형을 회전, 대칭시켜서 나올 수 있는 모든 경우의 수를 탐색하자

 

생각해볼 점

  • 백트래킹으로 풀 수 있을 것 같다. 도전해보기!

 

오답 분석

  • 좌표 계산 실수
  • 단순 구현으로 문제를 접근 하는 경우 실수하면 찾기 힘드므로 집중하기!

 

# 테트로미노
n,m=map(int,input().split())
map_data = [list(map(int,input().split())) for _ in range(n)]

t1 =[[[0,0],[1,0],[2,0],[3,0]],
     [[0,0],[0,1],[0,2],[0,3]]]

t2 = [[[0,0],[0,1],[1,0],[1,1]]]

t3 =[[[0,0],[1,0],[2,0],[2,-1]],
     [[0,0],[0,-1],[1,0],[2,0]],
     [[0,0],[1,0],[2,0],[2,1]],
     [[0,0],[1,0],[2,0],[0,1]],
     [[0,0],[0,-1],[0,-2],[1,0]],
     [[0,0],[-1,0],[0,-1],[0,-2]],
     [[0,0],[-1,0],[0,1],[0,2]],
     [[0,0],[1,0],[0,1],[0,2]]]

t4 = [[[0,0],[1,0],[1,1],[2,1]],
      [[0,0],[0,1],[-1,1],[-1,2]],
      [[0,0],[1,0],[1,-1],[2,-1]],
      [[0,0],[0,1],[1,1],[1,2]]]

t5 = [[[0,0],[0,1],[0,2],[1,1]],
      [[0,0],[0,1],[-1,1],[1,1]],
      [[0,0],[0,1],[0,2],[-1,1]],
      [[0,0],[1,0],[2,0],[1,1]]]

all_case=t1+t2+t3+t4+t5
max_sum=0
for i in range(n):
    for j in range(m):
        for tet in all_case:
            tmp = 0
            for tet_pos in tet:
                nx,ny=i+tet_pos[0],j+tet_pos[1]
                if 0<=nx<n and 0<=ny<m:
                    tmp+=map_data[nx][ny]
                else:
                    break
            max_sum=max(max_sum,tmp)
print(max_sum)

 

* 틀린 부분이나 더 나은 방법이 있을 수 있습니다. 지적해주시면 감사하겠습니다!!

[백준 14499번] 주사위 굴리기 - Python으로 구현하기

 

문제 접근

  • 주사위를 어떻게 자료구조로 표현하고 면 옮기기를 구현할 지가 관건
  • 주사위의 각 면을 1~6번으로 부여 한 뒤 주사위가 굴러질 때마다 면을 바꿔주는 방식을 택했다.

 

생각해볼 점

  • 기업 인적성에 나오는 정육면체 전개도 옮기기 구현?
  • 면 옮기는데 좀 더 편하고 가독성 좋은 방법?

 

오답 분석

  • 좌표 평면의 x,y와 문제의 x,y가 반대로 되어 있어서 틀린 사람이 많다.
  • 항상 문제 꼼꼼히 읽기 주의!

 

# 1 index, n*m 인 borad
import sys
input = lambda: sys.stdin.readline().rstrip()

n, m, x, y, k = map(int, input().split())
dice=[0]*(6+1)
board = [list(map(int, input().split())) for _ in range(n)]  # 맵 정보
opers = list(map(int, input().split()))  # 동쪽은 1, 서쪽은 2, 북쪽은 3, 남쪽은 4로 주어진다.
direc = {1: (0, 1), 2: (0, -1), 3: (-1, 0), 4: (1, 0)}

for oper in opers:
    dx,dy=direc.get(oper)   # get pos

    # move next pos
    x+=dx
    y+=dy
    if 0<=x<n and 0<=y<m:   # 다음 좌표 이동가능
        # 주사위 면을 교체
        if oper==1: # 동쪽
            dice[3],dice[1]=dice[1],dice[3]
            dice[1],dice[4]=dice[4],dice[1]
            dice[4],dice[6]=dice[6],dice[4]
        elif oper==2:   # 서
            dice[4], dice[1] = dice[1], dice[4]
            dice[1], dice[3] = dice[3], dice[1]
            dice[3], dice[6] = dice[6], dice[3]
        elif oper == 3: # 남 : 5 6 2 1
            dice[5], dice[1] = dice[1], dice[5]
            dice[1], dice[2] = dice[2], dice[1]
            dice[2], dice[6] = dice[6], dice[2]
        elif oper == 4: # 북
            dice[2], dice[1] = dice[1], dice[2]
            dice[1], dice[5] = dice[5], dice[1]
            dice[5], dice[6] = dice[6], dice[5]

        if board[x][y]==0: # 칸이 0 이면 -> 주사위에 있는값이 복사됨
            board[x][y]=dice[6]
        else:   # 주사위 값 교체
            dice[6]=board[x][y]
            board[x][y]=0
        print(dice[1])

    else:   # 인덱스 오류 -> 해당 명령어 무시, 좌표 원상복귀
        x-=dx
        y-=dy

 

* 틀린 부분이나 더 나은 방법이 있을 수 있습니다. 지적해주시면 감사하겠습니다!!

[백준 13458번] 시험 감독 python으로 구현하기

 

문제 접근

  • 각 방에 총감독관은 무조건 한명은 필요!
  • 나머지 인원은 부감독관이 해결
  • 하나의 시험장에 필요한 감독관 수 = 총감독관 1명 + 반올림((시험장 인원 - 총감독관 감시 가능 인원)%부감독관 감시 가능 인원)

 

생각해볼 점

  • 시간복잡도 : 시험장의 수만큼 반복문이 돌아야 되므로 O(시험장 개수) 이다.

 

오답 분석

  • 문제의 정답률이 낮은 원인을 Q&A에서 찾아보니 아래의 이유들이 대표적이다.
  • 자료형 범위 초과
  • 총감독관 혼자서 감시 가능한 경우 예외처리

 

# 시험 감독
# 응시생 모두 감시, 필요한 감독관의 수 최소값
import math
n = int(input())    # 시험장 개수
a = list(map(int,input().split()))  # 각 시험장 응시수
b,c = map(int,input().split())  # 총감독관 감시가능수, 부감독관 감시가능수

total_cnt=0
for i in range(n):
    # 총감독관
    res_ = a[i]-b if a[i]-b>0 else 0
    total_cnt+=1 + math.ceil(res_/c)
print(total_cnt)

 

* 틀린 부분이나 더 나은 방법이 있을 수 있습니다. 지적 해주시면 감사하겠습니다!!

[백준 3190번] 뱀 Python 으로 구현하기

 

  • 삼성 SW테스트 초창기 문제라 그런지 최근 문제들에 비해 비교적 조건이 적은 편
  • 주어진 조건들과 상황에 따라 그대로 코드로 옮기면 풀리는 시뮬레이션 유형의 문제
  • 아래 코드는 list.pop(0) 와 oper.pop(0)의 시간복잡도를 고려하지 않은 코드

 * 해당 코드에서 Python의 list 대신 deque 를 쓰면 pop 연산의 O(n)의 시간복잡도를 O(1)로 바꿀 수 있다!

 

# 백준 3190번 - 뱀
n=int(input())	# 맵크기
k=int(input())	# 사과

# 맵
board=[[0]*(n+1) for i in range(n+1)]
# 사과 정보
for _ in range(k):
    x,y=map(int,input().split())
    board[x][y]=1

# oper
oper=[input().split() for _ in range(int(input()))]
snake=[(1,1)]    # snake 몸
# 끝나는 경우 -> 맵 밖에 나감 or 자신의 몸에 닿음
# 뱀은 처음에 오른쪽을 향한다.
d = [(0,1),(1,0),(0,-1),(-1,0)] # 동남서북
d_f=0
score=0	# 시간
x,y=1,1

while True:
    score+=1
    # 다음 x,y
    x+=d[d_f][0]
    y+=d[d_f][1]
    if 1<=x<=n and 1<=y<=n:
        snake.append((x,y)) # 몸길이 늘림
        for i in snake[:-1]: # 자기 몸과 부딪힌경우
            if (x,y)==i:
                print(score)
                exit(0)
        if board[x][y]==0: # 그냥 통로임-> 꼬리 삭제
            snake.pop(0)
        if board[x][y]==1:
            board[x][y]=0
    else:   # 맵을 나간 경우
        print(score)
        break

    if oper and score==int(oper[0][0]):
        if oper[0][1]=='D': # 오른쪽 90
            d_f= d_f+1 if d_f<3 else 0
            oper.pop(0)
        elif oper[0][1]=='L': # 왼쪽 90
            d_f = d_f - 1 if d_f > 0 else 3
            oper.pop(0)

 

 

* 틀린 부분이나 더 나은 방법이 있을 수 있습니다. 지적해 주시면 감사하겠습니다!

 

+ Recent posts