direction = [0,1,2,3] # dire의 값이 0 : 좌 # 1: 하 # 2: 우 # 3: 상 move_dire = [[0,-1], [1,0], [0,1], [-1,0]] # 토네이도가 부는 방향 좌 하 우 상 # -90도 회전 list(zip(*tornado))[::-1] tornado = [[0,0,2,0,0], [0,10,7,1,0], [5,0,0,0,0], [0,10,7,1,0], [0,0,2,0,0]] N = int(input()) arr = [list(map(int,input().split())) for _ in range(N)] k = N**2 -1 cnt = 0 number_cnt = 1 # number_cnt는 현재 방향으로 진행되는 최대거리를 알려주는 것이다. double_cnt = 0 # 최대거리가 진행되는 횟수를 알려주는 것이다. cur_cnt = 0 # 현재 이동 횟수이다. cur_dire = 0 # 현재 진행 방향이다. # 이 문제에서 보면 알 수 있듯이, 좌하우상 순서로 진행되면 그 거리는 1,1,2,2,3,3,4,4,5,5,6,6 순으로 진행된다. # 최대거리가 동일한게 2번 반복되는 것을 알 수 있다. location = [N//2,N//2] result = 0 while True: # 최대 거리와 현재 이동거리가 같다면 방향이 바뀌어야하는 것이므로, 방향을 바꾸면서 최대거리를 갱신해주는 작업을 해준다. if cur_cnt == number_cnt: cur_cnt = 0 double_cnt += 1 cur_dire = (cur_dire+1)%4 tornado = list(zip(*tornado))[::-1] # -90도 회전을 해주는 간편한 방법이다. if double_cnt == 2: # double_cnt가 2라는 것은 최대 이동거리가 동일한게 2번 반복된것이니, 최대 이동거리를 증가시켜줘야한다. double_cnt = 0 number_cnt += 1 # target_location은 현재 토네이도의 위치인 x에서 y로 갈때 y의 위치이다. target_location = [location[0]+move_dire[cur_dire][0],location[1]+move_dire[cur_dire][1]] # total_more는 targetloaction에 있는 모래의 양이다. total_more = arr[target_location[0]][target_location[1]] # torandao로 이동하는 것을 해주는 것이다. for i in range(5): for j in range(5): move_ind = [target_location[0]+i-2,target_location[1]+j-2] more = int(tornado[i][j]*arr[target_location[0]][target_location[1]]/100) if 0<=move_ind[0]<N and 0<=move_ind[1]<N: arr[move_ind[0]][move_ind[1]] += more # 만약 범위를 벗어나면, 결과값에 추가해준다. else: if more: result += more # 흩날리고 남은 모래를 a의 모래가 되므로 구해준다. total_more -= more cur_cnt += 1 last_location = [location[0]+2*move_dire[cur_dire][0],location[1]+2*move_dire[cur_dire][1]] # a의 위치가 범위를 벗어나면, result에 추가해주고, 아니면 해당위치에 모래를 추가해준다. if 0<=last_location[0]<N and 0<=last_location[1]<N: arr[last_location[0]][last_location[1]] += total_more else: result += total_more location = [location[0]+move_dire[cur_dire][0],location[1]+move_dire[cur_dire][1]] arr[location[0]][location[1]] = 0 if location[0] == 0 and location[1] == 0: break print(result)
처음 풀었던 방식은 문제에 나와있는걸 그대로 구현해주었다.
이 문제를 풀때 중요한것은 방향전환과 그 반복성이 어떻게 진행되는지 찾아주고 그것을 구현해주는 방식이다.
하지만 코드길이가 길고, 변수도 많아서 문제를 풀때 헷갈리는게 많았다.
import sys def blowSand(x,y,dire): global N ret = 0 init_sand = arr[x][y] for i in range(10): if i == 9: sand = arr[x][y] else: sand = int(init_sand * rate[i]/100) arr[x][y] -= sand move_x = x + blowx[dire][i] move_y = y + blowy[dire][i] if 0<=move_x<N and 0<=move_y<N: arr[move_x][move_y] += sand else: ret += sand arr[x][y] = 0 return ret dx = [0,1,0,-1] dy = [-1,0,1,0] rate = [1, 1, 7, 7, 10, 10, 2, 2, 5] blowx = [[-1, 1, -1, 1, -1, 1, -2, 2, 0,0], #left [-1, -1, 0, 0, 1, 1, 0, 0, 2,1], #down [-1, 1, -1, 1, -1, 1, -2, 2, 0,0], #right [1, 1, 0, 0, -1, -1, 0, 0, -2,-1],] #up blowy = [[1, 1, 0, 0, -1, -1, 0, 0, -2,-1], #left [-1, 1, -1, 1, -1, 1, -2, 2, 0,0], #down [-1, -1, 0, 0, 1, 1, 0, 0, 2,1], #right [-1, 1, -1, 1, -1, 1, -2, 2, 0,0]] #up N = int(sys.stdin.readline()) arr =[list(map(int,sys.stdin.readline().split())) for _ in range(N)] x,y = N//2,N//2 i = 1 dire = 0 result = 0 while i<=N: j = 0 while j <int(i): x = x + dx[dire%4] y = y + dy[dire%4] result += blowSand(x,y,dire%4) j += 1 dire += 1 i += 0.5 print(result)
위의 코드는 클론코딩한 것으로, 기본적인 원리는 위와 비슷하지만 좀 더 깔끔해서 보기가 편하다.
모래방향에 따른 x,y의 이동값을 전부 저장해준다. 그리고 그에 맞게 이동시 날라가는 비율을 적어준다.
여기서는 위에서 내가 했던 double_cnt 같은 것을 이용하지 않고 0.5 단위로 i의 값을 올려주고, 그것을 int화 함으로서 2번반복을 구현해냈다.
blowSand라는 함수를 통해, 날라간 모래 양을 계속 더해주고, 모래가 날라간 상황을 만들어줬다.
'알고리즘 > 백준' 카테고리의 다른 글
[BOJ] 20055 컨베이어 벨트 위의 로봇 (0) | 2021.01.10 |
---|---|
[BOJ] 20056 마법사 상어와 파이어볼 (0) | 2021.01.10 |
[BOJ] 7562 나이트의 이동 (0) | 2021.01.10 |
[BOJ] 16918 봄버맨(풀이 방식 2종류) (0) | 2021.01.10 |
[BOJ] 16236 아기상어 (0) | 2021.01.10 |