728x90

https://swexpertacademy.com/main/code/problem/problemDetail.do?contestProbId=AV5PzOCKAigDFAUq 

 

SW Expert Academy

SW 프로그래밍 역량 강화에 도움이 되는 다양한 학습 컨텐츠를 확인하세요!

swexpertacademy.com

 

 

문제)

 

 

 

풀이)

아주 간단한 문제!

N크기도 작아서 for문으로 충분히 해결할 수 있다고 생각했다.

 

네모칸을 차례대로 움직이면서, 값을 모두 더한 후 비교하는 방식을 이용했는데,

범위만 주의하면 간단하다.

 

 

Python 코드

T = int(input())
for test_case in range(1, T + 1):
    n, m = map(int, input().split())
    matrix = []
    for _ in range(n):
        matrix.append(list(map(int, input().split())))

    answer = 0
    for i in range(n-m+1):
        for j in range(n-m+1):
            num = 0
            for row in range(m):
                for col in range(m):
                    num += matrix[row+i][col+j]
            if answer < num:
                answer = num
			           

    print('#{} {}'.format(test_case, answer))

 

 

JAVA 코드

import java.util.Scanner;
import java.io.FileInputStream;

class Solution
{
	public static void main(String args[]) throws Exception
	{
		Scanner sc = new Scanner(System.in);
		int T;
		T=sc.nextInt();
		for(int test_case = 1; test_case <= T; test_case++)
		{
		int N = sc.nextInt();
			int M = sc.nextInt();
			int[][] matrix = new int[N][N];
			for(int i=0; i<N; i++) {
				for(int j=0; j<N; j++) {
					matrix[i][j] = sc.nextInt();
				}
			}
			
			int answer = 0;
			for(int row=0; row<N-M+1; row++) {
				for(int col=0; col<N-M+1; col++) {
					int num=0;
					for(int i=0; i<M; i++) {
						for(int j=0; j<M; j++) {
							num += matrix[row+i][col+j];
						}
					}
					if(answer<num)
						answer=num;
				}
			}
			System.out.println("#"+test_case+" "+answer);

		}
	}
}
728x90

'코테 > SWEA' 카테고리의 다른 글

SWEA 1228 암호문1(JAVA)  (0) 2022.08.19
SWEA 1225. 암호생성기(JAVA)  (0) 2022.08.16
SWEA 1218. 괄호 짝짓기(JAVA)  (0) 2022.08.12
SWEA 2805. 농작물 수확하기(JAVA)  (0) 2022.08.12
SWEA 1873. 상호의 배틀필드(JAVA)  (0) 2022.08.10
728x90

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

 

7576번: 토마토

첫 줄에는 상자의 크기를 나타내는 두 정수 M,N이 주어진다. M은 상자의 가로 칸의 수, N은 상자의 세로 칸의 수를 나타낸다. 단, 2 ≤ M,N ≤ 1,000 이다. 둘째 줄부터는 하나의 상자에 저장된 토마토

www.acmicpc.net

 

 

문제)

 

 

 

해설)

이 문제는 당연히 bfs로 풀어야지!! 하면서 좀 헤맸다..ㅎㅎ

두 가지 방식으로 했는데, 코드는 두 번째가 조금 더 깔끔한 것 같다.

 

 

 

풀이 1)

from collections import deque

def bfs(tomato):
    global box
    dx = [0, 0, -1, 1]
    dy = [1, -1, 0, 0]
    count = 0
    while tomato:
        second = []
        t_li = tomato.popleft()
        for t_mem in t_li:
            x, y = t_mem[0], t_mem[1]
            for i in range(4):
                nx = x + dx[i]
                ny = y + dy[i]
                if 0 <= nx < n and 0 <= ny < m:
                    if box[nx][ny] == 0:
                        second.append([nx, ny])
                        box[nx][ny] = 1
                    else:
                        continue
        if second != []:
            tomato.append(second)
        count += 1
    return count - 1

m, n = map(int, input().split()) # m: col, n: row
box = []
tomato = deque()
for i in range(n):
    box.append(list(map(int, input().split())))

first = []
for i in range(n):
    for j in range(m):
        if box[i][j] == 1:
            first.append([i, j])
tomato.append(first)


day = bfs(tomato)
for i in range(n):
    for j in range(m):
        if box[i][j] == 0:
            print(-1)
            exit(0)
print(day)

bfs 함수 내에서 며칠이나 걸렸는지 반환해주려고 이 코드를 짜게 되었다.

한 박스에 토마토가 여러 개일 경우 동시에 토마토가 있는 좌표의 옆 토마토들이 익는다.

따라서 하루 단위로 익을 토마토(box에서 0인 애들) list(first, second)를 만들어 저장하고, 그것을 tomato라는 queue에 저장하는 방식으로 구현했다.

 

tomato에서 하나를 뽑으면 그 list에 해당하는 좌표를 순회하고, 해당 list에 저장된 좌표를 모두 돌면 하루가 늘어나는 방식이다.

하지만 여기에는 처음에 토마토가 있던 위치도 하루가 지난 것으로 치는 방식이기에 1을 뺀 값을 반환한다.

 

bfs가 모두 끝나면 혹시 토마토가 익지 않은 경우가 있을 수 있기 때문에 확인해준다.

여기에서 익지 않은 토마토가 있을 경우 -1을 출력하고 exit 하여 끝낸다.

그렇지 않다면 bfs 결과를 출력해준다.

 

 

 

풀이 2)

from collections import deque

def bfs(tomato):
    global box
    dx = [0, 0, -1, 1]
    dy = [1, -1, 0, 0]
    while tomato:
        x, y = tomato.popleft()
        for i in range(4):
            nx = x + dx[i]
            ny = y + dy[i]
            if 0 <= nx < n and 0 <= ny < m:
                if box[nx][ny] == 0:
                    tomato.append([nx, ny])
                    box[nx][ny] = box[x][y] + 1
                else:
                    continue


m, n = map(int, input().split()) # m: col, n: row
box = []
tomato = deque()
for i in range(n):
    box.append(list(map(int, input().split())))

for i in range(n):
    for j in range(m):
        if box[i][j] == 1:
            tomato.append([i, j])


day = 0
bfs(tomato)
for i in box:
    for j in i:
        if j == 0:
            print(-1)
            exit(0)
    day = max(day, max(i))
print(day - 1)

이 풀이도 똑같이 bfs를 활용했다.

다른 점은 좌표를 차례대로 queue인 tomato에 저장해주고, bfs를 하는 도중 다음 좌표의 box 값이 0이라면 원좌표의 값에 +1을 해주는 방식을 사용했다. 

 

또한 이 방식도 처음 토마토의 위치가 1이어서 하루가 더 더해진 방식이므로 box에 0이 없음을 확인하면 1을 뺀 값을 출력해준다.

 

728x90

'코테 > DFS, BFS' 카테고리의 다른 글

[DFS/BFS] 백준 2606 바이러스(DFS 풀이)  (0) 2022.06.06
[DFS/BFS] 미로 탈출  (0) 2022.06.04
[DFS/BFS] 음료수 얼려 먹기  (0) 2022.06.03
[DFS/BFS] 이론  (0) 2022.04.26
728x90

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

 

20207번: 달력

 수현이는 일년의 날짜가 1일부터 365일로 표시되어있는 달력을 가지고있다. 수현이는 너무나도 계획적인 사람이라 올 해 일정을 모두 계획해서 달력에 표시해놨다.  여름이 거의 끝나가자 장

www.acmicpc.net

 

 

문제)

 

 

 

풀이)

 

구현 문제인데 직사각형을 표현하는 방법을 어떻게 표현해야 할지 고민이 많았다. 결국 해결 못해서 이것저것 검색해봄..ㅎ

직사각형은 row, col을 구해야하므로 이를 생각해야 한다.

 

 

row는 어떤 날짜에 일정이 몇 개가 있는지에 따라 다르다. 이것은 문제에 있는 그림을 보면 이해하기 쉬울 것이다.

따라서 row를 구하기 위해 일정을 schedule이라는 일차원 배열에 저장한다. 여기에서 가장 큰 것이 row가 될 것이다.

 

 

col은 schedule에 저장한 값이 0이 아닌 것들이 연속된 개수이다. 따라서 schedule의 값을 확인하여 col 값을 구한다.

schedule 값이 0이라면 직사각형 하나가 만들어진 것이므로 row * col 값을 정답에 저장해준다.

 

 

이때, 만약 schedule의 맨 마지막 index인 365에서 0이 아닌 값이 존재한다면 정답에 row*col 값을 저장해 줄 수 없다.

따라서 이에 해당하는 조건을 달아 해결해준다.

 

 

소스코드)

n = int(input())
schedule = [0] * 366
for i in range(n):
    start, end = map(int, input().split())
    for j in range(start, end+1):
        schedule[j] += 1

row = 0
col = 0
answer = 0
for i in range(1, len(schedule)):
    if schedule[i] != 0:
        col += 1
        row = max(row, schedule[i])
    else:
        answer += row * col
        row = 0
        col = 0
    # 만약 맨 마지막에 일정이 존재한다면 정답에 업데이트가 되지 않는다. 따라서 새로운 if문 생성
    if i == len(schedule)-1:
        answer += row * col
print(answer)
728x90

'코테 > Implementation(구현)' 카테고리의 다른 글

[Implementation] 게임 개발  (0) 2022.04.26
[Implementation] 왕실의 나이트  (0) 2022.03.21
[Implementation] 시각  (0) 2022.03.21
[Implementation] 상하좌우  (0) 2022.03.17
[Implementation] 이론  (0) 2022.03.17
728x90

정렬(Sorting)

데이터를 특정한 기준에 따라서 순서대로 나열하는 것

 

선택 정렬(Selection Sort)

가장 작은 데이터를 선택 -> 맨 앞에 있는 데이터와 교환 -> 그 다음 작은 데이터를 선택 -> 앞에서 두 번째 데이터와 교환

 

예시)

 

7 5 9 0 3 1 6 2 4 8

 

가장 작은 데이터인 '0'와 맨 앞 데이터인 '7'을 교환한다.

 

0 5 9 7 3 1 6 2 4 8

 

그 다음 작은 데이터인 '1'과 두 번째 데이터인 '5'를 교환한다.

 


 

0 1 2 3 4 5 6 7 9 8

 

위의 과정을 9번 반복하면 다음과 같이 정렬이 완료된다.

 

0 1 2 3 4 5 6 7 8 9

 

선택 정렬은 데이터 교환 과정을 N-1번 반복하면 완료된다.

 

 

 

선택 정렬 소스코드)

array = [7, 5, 9, 0, 3, 1, 6, 2, 4, 8]

for i in range(len(array)):
    min_index = i	# 가장 작은 원소 인덱스
    for j in range(i+1, len(array)):
    	if array[min_index] > array[j]:
        	min_index = j
    array[i], array[min_index] = array[min_index], array[i]	# 교환
    
print(array)

시간 복잡도: O(N^2)으로 느린 편이다.

하지만 코테에서는 가장 작은 인덱스를 찾는 과정이 있으므로 위의 과정은 익숙해지는 것이 좋다.

 

 

 

삽입 정렬(Insertion Sort)

특정한 데이터를 적절한 위치에 삽입하는 정렬. 이때 삽입되기 이전, 그 앞까지의 데이터는 이미 정렬되어 있다고 가정한다.

 

예시)

 

7 5 9 0 3 1 6 2 4 8

 

첫 번째 데이터인 '7'은 그 자체로 정렬되어 있다고 판단하고, 두 번째 데이터인 '5'가 어떤 위치로 들어갈지 판단한다.

'7'의 왼쪽 또는 오른쪽 중에서 결정하는데 왼쪽에 삽입한다.

(본 위치에서 왼쪽으로 차례차례 확인하는 것)

 

5 7 9 0 3 1 6 2 4 8

 

다음 '9'가 어느 위치에 들어갈지 판단한다. 들어갈 수 있는 위치는 총 3가지이다.

'5'의 왼쪽, 오른쪽, 그리고 '7'의 오른쪽이다.

적절한 위치는 '7'의 오른쪽이므로 그대로 둔다.

 

5 7 9 0 3 1 6 2 4 8

 

'0'은 총 4가지의 위치 중 '5'의 왼쪽에 해당하므로 해당 위치에 삽입한다.

 

0 5 7 9 3 1 6 2 4 8

 

'3'은 '0'과 '5'사이에 삽입한다.

 


 

0 1 2 3 4 5 6 7 9 8

 

위의 과정을 N-1번 반복하면 다음과 같이 정렬이 완료된다.

 

0 1 2 3 4 5 6 7 8 9

 

삽입 정렬의 특징으로는 정렬이 이루어진 원소는 항상 오름차순이다.(내림차순으로 정렬했다면 내림차순!)

예시의 파란색 숫자를 보면 이해하기 편하다.

따라서 삽입 위치를 선정할 때, 삽입될 데이터보다 작은 데이터를 만나면, 그 위치에 멈추면 된다.

 

 

삽입 정렬 소스코드)

array = [7, 5, 9, 0, 3, 1, 6, 2, 4, 8]

for i in range(1, len(array)):
    for j in range(i, 0, -1):
        if array[j] < array[j-1]:	# 한 칸씩 왼쪽으로 이동
            array[j], array[j-1] = array[j-1], array[j]
        else:	# 자기보다 작은 데이터를 만나면 그 위치에서 멈추기
            break
    
print(array)

시간 복잡도: O(N^2)

단, 최선의 경우(현재 리스트의 데이터가 거의 정렬되어 있는 상태) 시간 복잡도: O(N)

 

 

 

퀵 정렬(Quick Sort)

기준 데이터(pivot)를 설정하고 그 기준보다 큰 데이터와 작은 데이터의 위치를 바꾸는 정렬

가장 많이 사용하는 정렬!

 

예시)

 

5 7 9 0 3 1 6 2 4 8

 

처음 pivot을 설정할 땐 맨 처음 데이터로 설정한다.

2번째 데이터부터 차례로 오른쪽으로 가면서 pivot보다 작은 수를 찾는다.

맨 끝 데이터부터 차례로 왼쪽으로 가면서 pivot보다 큰 수를 찾는다.

 

5 4 9 0 3 1 6 2 7 8

 

찾은 후에는 데이터를 교환한다.

이를 pivot보다 작은 수pivot보다 큰 수위치가 엇갈릴 때까지 반복한다.

 


 

5 4 2 0 3 1 6 9 7 8

 

엇갈릴 때 pivot과 pivot보다 작은 수를 교환한다!

즉, 위의 예시에서는 1과 5를 교환한다.

 

1 4 2 0 3 5 6 9 7 8

 

그렇다면 pivot인 5를 기준으로 왼쪽은 pivot보다 작은 수, 오른쪽은 pivot보다 큰 수로 구성된다.

이 상태에서, 왼쪽과 오른쪽을 각각 또 정렬한다!

이 과정을 반복하면 전체 정렬이 완료된다.

 

0 1 2 4 3 5 6 9 7 8
0 1 2 4 3 5 6 8 7 9
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9

 

위의 예시에 해당하는 quick sort를 실행한 결과를 보여준 것이다.

각 과정에서 pivot을 표시했다.

 

 

퀵 정렬 소스코드)

array = [5, 7, 9, 0, 3, 1, 6, 2, 4, 8]

def quick_sort(array, start, end):
    if start >= end:    # 원소가 1개인 경우 종료
        return
    pivot = start   # pivot은 첫 번째 원소
    left = start + 1
    right = end
    while left <= right:
        # pivot보다 큰 데이터 찾을때까지 반복
        while left <= end and array[left] <= array[pivot]:
            left += 1
        # pivot보다 작은 데이터 찾을때까지 반복
        while right >= start and array[right] >= array[pivot]:
            right -= 1
        if left > right:    # 엇갈린다면 작은 데이터와 pivot 교체
            array[right], array[pivot] = array[pivot], array[right]
        else:
            array[left], array[right] = array[right], array[left]
        
    # 분할 이후 왼쪽 부분과 오른쪽 부분에서 각각 정렬 수행
    quick_sort(array, start, right - 1)
    quick_sort(array, right+1, end)

quick_sort(array, 0, len(array) - 1)
print(array)

# [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

 

시간 복잡도:

평균 시간 복잡도: O(NlogN)

최악 시간 복잡도: O(N^2) => 데이터가 이미 정렬되어 있을 경우!

 

 

 

계수 정렬(Count Sort)

특정한 조건이 부합할 때만 사용할 수 있는 알고리즘. 매우 빠르다!

최악의 경우에도 O(N + K)를 보장한다.(K: 데이터 중 최댓값)

 

하지만, 데이터의 크기 범위가 제한되어 정수 형태로 표현 가능할 경우에만 사용할 수 있다.

일반적으로 가장 큰 데이터와 가장 작은 데이터의 차이가 1,000,000을 넘지 않을 때 사용 가능하다.

위에 해당하는 이유는 모든 범위를 담을 수 있는 크기의 배열을 선언해야 하기 때문이다.

 

방법:

가장 큰 데이터와 가장 작은 데이터의 범위가 모두 담긴 하나의 리스트 생성 -> 리스트의 모든 데이터를 0으로 초기화 -> 데이터를 하나씩 확인하며 데이터의 값과 동일한 인덱스의 데이터를 1씩 증가

 

예시)

 

7 5 9 0 3 1 6 2 9 1 4 8 0 5 2

0 2 3 4 5 6 7 8 9
0 0 0 0 0 0 0 1 0 0

 

데이터 7에 해당하는 인덱스의 값을 1 늘려준다.

 

7 5 9 0 3 1 6 2 9 1 4 8 0 5 2

0 2 3 4 5 6 7 8 9
0 0 0 0 0 1 0 1 0 0

 

데이터 5에 해당하는 인덱스의 값을 1 늘려준다.

이를 반복하면 다음과 같다.

 

7 5 9 0 3 1 6 2 9 1 4 8 0 5 2

0 2 3 4 5 6 7 8 9
2 2 2 1 1 2 1 1 1 2

 

결과적으로 리스트에는 각 데이터가 몇 번 등장했는지 횟수가 기록된다.

이것 자체가 정렬된 형태라고 볼 수 있다!

출력만 하면 완료됨!!

 

 

계수 정렬 소스코드)

# 모든 원소의 값이 0보다 크거나 같다고 가정
array = [7, 5, 9, 0, 3, 1, 6, 2, 9, 1, 4, 8, 0, 5, 2]
# 모든 범위를 포함하는 리스트 선언(모든 값 0으로 초기화)
count = [0] * (max(array) + 1)

for i in range(len(array)):
    count[array[i]] += 1    # 각 데이터에 해당하는 인덱스의 값 증가

for i in range(len(count)): # 리스트에 기록된 정렬 정보 확인
    for j in range(count[i]):
        print(i, end = ' ')

# 0 0 1 1 2 2 3 4 5 5 6 7 8 9 9

 

시간 복잡도: O(N + K)

공간 복잡도: O(N + K)

계수 정렬은 데이터의 크기가 한정되어 있고, 데이터의 크기가 많이 중복되어 있을수록 적합하다!

 

 

 

728x90
728x90

"이것이 코딩테스트다" 책 문제 _ DFS/BFS 문제

문제)

NxM 크기의 직사각형 형태의 미로가 있다. 미로에는 여러 마리의 괴물이 있어 이를 피해 탈출해야 한다. 현재 위치는 (1, 1)이고 미로의 출구는 (N, M)의 위치에 존재하며 한 번에 한 칸씩 이동할 수 있다. 이때 괴물이 있는 부분은 0으로, 괴물이 없는 부분은 1로 표시되어 있다. 미로는 반드시 탈출할 수 있는 형태로 제시된다. 이때 탈출하기 위해 움직여야 하는 최소 칸의 개수를 구해라. 칸을 셀 때는 시작 칸과 마지막 칸을 모두 포함해서 계산한다.

 

입력조건

  • 첫째 줄에 두 정수 N, M(4 <= N, M <= 200)이 주어진다. 다음 N개의 줄에는 각각 M개의 정수(0 혹은 1)로 미로의 정보가 주어진다. 각각의 수들은 공백 없이 붙어서 입력으로 제시된다. 또한 시작 칸과 마지막 칸은 항상 1이다.

 

출력조건

  • 첫째 줄에 최소 이동 칸의 개수를 출력한다.

 

입력예시)
5 6
101010
111111
000001
111111
111111
출력예시)
10

 

 

 

 

 

풀이)

이 문제는 BFS 문제로 해결했다! (1, 1)에서 시작하여 주변을 탐색하며 1이 있는 부분을 택해서 가기 때문에 모든 노드를 탐색하므로 BFS가 편리하다고 생각했다. 사실 BFS로 해결을 하는 부분까진 감을 잡았는데 최소 이동 칸의 개수를 세는 방법을 잘 캐치를 못했다.

코드는 다음과 같다.

 

from collections import deque
N, M = map(int, input().split())
maze = []
for i in range(N):
    maze.append(list(map(int, input())))

# 첫 번째 칸 무조건 포함
count = 1
# 상 하 좌 우
dx = [-1, 1, 0, 0]
dy = [0, 0, -1, 1]

#bfs
def bfs(x, y):
    que = deque()
    que.append((x, y))
    while que:
        x, y = que.popleft()
        for i in range(4):
            nx = x + dx[i]
            ny = y + dy[i]
            if nx < 0 or nx >= N or ny < 0 or ny >= M:
                continue
            if maze[nx][ny] == 0:
                continue
            if maze[nx][ny] == 1:
                maze[nx][ny] = maze[x][y] + 1
                que.append((nx, ny))
    return maze[N-1][M-1]


print(bfs(0, 0))
print(maze)


# 결과: 10
# maze
# [[3, 0, 5, 0, 7, 0], 
#  [2, 3, 4, 5, 6, 7], 
#  [0, 0, 0, 0, 0, 8], 
#  [14, 13, 12, 11, 10, 9], 
#  [15, 14, 13, 12, 11, 10]]

노드를 방문했을때 길이 존재한다면 '이전 노드 값 + 1'을 저장한다!

맨 마지막 노드까지 bfs를 진행한다면 맨 마지막 노드에는 전체 거리 값이 저장된다.

다만 여기에서 maze 전체를 출력해본 값을 본다면 알 수 있듯이 시작 위치가 1이 아닌 3으로 변경된다.

왜냐하면 코드 상에서는 첫 번째 노드를 다시 방문할 수 있게 되어있기 때문이다!!

하지만 문제를 푸는 데에는 이상이 없기 때문에 참고 사항으로 알아두면 좋을 것 같다.

728x90

'코테 > DFS, BFS' 카테고리의 다른 글

[DFS/BFS] 백준 7576 토마토  (0) 2022.06.07
[DFS/BFS] 백준 2606 바이러스(DFS 풀이)  (0) 2022.06.06
[DFS/BFS] 음료수 얼려 먹기  (0) 2022.06.03
[DFS/BFS] 이론  (0) 2022.04.26
728x90

"이것이 코딩테스트다" 책 문제 _ DFS/BFS 문제

NxM 크기의 얼음 틀이 있다. 구멍이 뚫려 있는 부분은 0, 칸막이가 존재하는 부분은 1로 표시된다. 구멍이 뚫려 있는 부분끼리 상, 하, 좌, 우로 붙어 있는 경우 서로 연결되어 있는 것으로 간주한다. 이때 얼음 틀의 모양이 주어졌을 때 생서오디는 총 아이스크림의 개수를 구하는 프로그램을 작성해라.

 

예시) 4x5 얼음틀 : 아이스크림 3개 생성

0 0 1 1 0
0 0 0 1 1
1 1 1 1 1
0 0 0 0 0

 

입력조건

  • 첫 번째 줄에 얼음 틀의 세로 길이 N과 가로 길이 M이 주어진다.(1 <= N, M <= 1000)
  • 두 번째 줄부터 N+1번째 줄까지 얼음 틀의 형태가 주어진다.
  • 이때 구멍이 뚫려잇는 부분은 0, 그렇지 않은 부분은 1이다.

출력조건

  • 한 번에 만들 수 있는 아이스크림의 개수를 출력한다.

 

입력예시)
15 14
00000111100000
11111101111110
11011101101110
11011101100000
11011111111111
11011111111110
11000000011111
01111111111111
00000000011111
01111111111000
00011111111000
00000001111000
11111111110011
11100011111111
11100011111111
출력예시)
8

 

 

 

풀이)

이 문제는 DFS로 풀어보았다! 전형적인 문제가 아닐까 생각한다.

N, M = map(int, input().split())
ice = []
for i in range(N):
    ice.append(list(map(int, input())))


def dfs(x, y):
    global N, M
    if x < 0 or x >= N or y < 0 or y >= M:
        return False
    if ice[x][y] == 0:
        ice[x][y] = 1
        dfs(x-1, y)
        dfs(x, y-1)
        dfs(x+1, y)
        dfs(x, y+1)
        return True
    return False

count = 0
for i in range(N):
    for j in range(M):
        if dfs(i, j) == True:
            count += 1

print(count)

얼음판 ice 구조를 이중 list로 저장해주고, (0, 0)부터 차례로 순회한다.

순회할때는 좌표 범위를 확인하고 0일경우 1로 바꿔준다.

dfs를 실행중인 좌표 기준으로 좌, 우, 상, 하를 똑같이 dfs로 순회한다.

return 값이 True로 끝나면 순회 완료! False 일 경우는 범위를 넘었거나 1인 경우이다.

 

 

또한 BFS로도 풀어보았다!!! (책은 DFS에 해당하는 풀이만 나와있다.)

from collections import deque

N, M = map(int, input().split())
ice = []
for i in range(N):
    ice.append(list(map(int, input())))
dx = [-1, 1, 0, 0]
dy = [0, 0, 1, -1]

def bfs(i, j):
    queue = deque()
    if ice[i][j] == 0:
        queue.append([i, j])
        while queue:
            x, y = queue.popleft()
            for p in range(4):
                nx = x + dx[p]
                ny = y + dy[p]
                if 0 <= nx < N and 0 <= ny < M:
                    if ice[nx][ny] == 0:
                        ice[nx][ny] = 1
                        queue.append([nx,ny])
                    else:
                        continue
                else:
                    continue
        return 1
    else:
        return 0



count = 0
for i in range(N):
    for j in range(M):
        count += bfs(i, j)
print(count)

좌, 우, 상, 하 이동을 dx, dy를 생성하여 만들었다. dfs와 같이 순회는 (0, 0) 부터 시작한다.

Ice가 0일 경우만 queue에 삽입 후 bfs를 진행하고, 아닐 경우는 없는 경우로 판단해 return 0한다.

다음 좌표의 ice가 0일 경우 1로 바꾸고 queue에 삽입한다. 이것을 queue가 다 끝날때까지 반복!

queue가 다 끝나면 해당 좌표의 bfs가 끝난 것이므로 1을 return해준다.

그리고 bfs 개수를 모두 더해주면 끝!!

 

 

728x90

'코테 > DFS, BFS' 카테고리의 다른 글

[DFS/BFS] 백준 7576 토마토  (0) 2022.06.07
[DFS/BFS] 백준 2606 바이러스(DFS 풀이)  (0) 2022.06.06
[DFS/BFS] 미로 탈출  (0) 2022.06.04
[DFS/BFS] 이론  (0) 2022.04.26
728x90

1. ord(): 문자를 아스키 코드로!

ord(문자)를 넣으면 문자에 해당하는 아스키 코드를 정수(int)로 반환해 준다.

col = ord('a')
print(col)

#97

 

2. chr(): 아스키 코드를 문자로!

chr(숫자)를 넣으면 숫자에 해당하는 아스키 코드를 문자(str)로 반환해 준다. 숫자는 정수이다.

col = chr(97)
print(col)

#a

 

728x90

'Python' 카테고리의 다른 글

[Python] map 함수  (0) 2022.03.04
728x90

"이것이 코딩테스트다" 책 문제 _ 구현 문제

문제)

정수 N이 입력되면 00시 00분 00초부터 N시 59분 59초까지의 모든 시각 중에서 3이 하나라도 포함되는 모든 경우의 수를 구하는 프로그램을 작성해라.

 

 

입력 조건

  • 첫째 줄에 정수 N이 입력된다.(0 <= N <= 23)

 

출력 조건

  • 00시 00분 00초부터 N시 59분 59초까지의 모든 시각 중에서 3이 하나라도 포함되는 모든 경우의 수를 출력한다.

 

입력 예시)
5
출력 예시)
11475

 

 

 

 

풀이)

모든 시각의 경우의 수를 세면 가능한 문제다. 즉, 이 문제는 완전 탐색 문제이다.

시간, 분, 초를 3중 반복문을 이용하여 3이 존재하는지 확인한다.

3이 존재하는지 확인하는 방법을 생각했을 때 int로는 확인하기 어려우므로 string으로 바꾸어서 시, 분, 초를 합친 후 3이 존재하는지 확인한다. 

예를 들어 03시 11분 05초의 경우 string으로 바꾸어 합치면 '3115'이므로 count 한다. (0을 꼭 포함해서 넣을 필요는 없으니까!)

N = int(input())
num = range(60)
count = 0
for i in range(N+1):
    for j in num:
        for k in num:
            if '3' in str(i) + str(j) + str(k):
                count += 1

print(count)
728x90

'코테 > Implementation(구현)' 카테고리의 다른 글

[Implementation] 백준 20207 달력  (0) 2022.06.06
[Implementation] 게임 개발  (0) 2022.04.26
[Implementation] 왕실의 나이트  (0) 2022.03.21
[Implementation] 상하좌우  (0) 2022.03.17
[Implementation] 이론  (0) 2022.03.17
728x90

"이것이 코딩테스트다" 책 문제 _ greedy 책 문제

문제)

어떠한 수 N이 1이 될 때까지 다음의 두 과정 중 하나를 반복적으로 선택하여 수행하려고 한다. 단, 두 번째 연산은 N이 K로 나누어 떨어질 때만 선택할 수 있다.

 

  1. N에서 1을 뺀다.

  2. N을 K로 나눈다.

 

N과 K가 주어질 때 N이 1이 될 때까지 1번 혹은 2번의 과정을 수행해야 하는 최소 횟수를 구하는 프로그램을 작성해라.

 

입력조건

  • 첫째 줄에 N(2 <= N <= 100,000)과 K(2 <= K <= 100,000)가 공백으로 구분되며 각각 자연수로 주어진다. 이때 입력으로 주어지는 N은 항상 K보다 크거나 같다.

 

출력조건

  • 첫째 줄에 N이 1이 될 때까지 1번 혹은 2번의 과정을 수행해야 하는 횟수의 최솟값을 출력한다.

 

 

 

풀이)

N이 1이 되기 위해 횟수가 가장 최소가 되려면 빼는 것 보다 나누는 과정이 숫자를 1에 가장 빨리 도달하게 할 수 있는 방법이다.

즉, 나누기를 최대한 많이 실행하면 된다.

따라서 N을 K로 나누어 떨어질 때까지 뺀 후, K로 나누는 과정을 반복하면 된다.

 

예를 들어 N = 17, K = 3일 경우 연산 과정은 다음과 같다.

단계 연산 과정 N
0(초기)   N = 17
1 1 빼기 N = 16
2 1 빼기 N = 15
3 K로 나누기 N = 5
4 1 빼기 N = 4
5 1 빼기 N = 3
6 K로 나누기 N = 1

 

이를 구현한 코드는 다음과 같다.

N, K = map(int, input().split())
count = 0

while (N > 1) :
    if N % K == 0:
        N = N // K
    else:
        N -= 1
    count += 1

print(count)

N이 1이 될 때까지 진행하기 때문에 while문의 조건은 N이 1보다 클 때이다.

while문 내에서 N이 K로 나누어 떨어질 경우 N은 K로 나누었을 때 몫으로 되고, K로 나누어 떨어지는 경우가 아닐 때 N에서 1씩 뺀다.

이때 연산 횟수를 count 변수에 1씩 더하여 저장한다.

 

 

 

문제에서는 N의 범위가 10만 이하이므로, 일일히 1씩 빼도 문제가 없지만, N이 100억 이상일경우 효율성 문제가 발생할 수 있다. 따라서 N이 K의 배수가 되도록 한 번에 빼는 방식으로 작성할 수 있다.

 

정답 예시)

N, K = map(int, input().split())
count = 0

while True:
    target = (N // K) * K
    count += N - target
    N = target

    if N < K:
        break
    count += 1
    N //= K

count += (N - 1)
print(count)

target을 N보다 작지만 가장 큰, K로 나누어 떨어지는 수이고, count에 N과 target의 차이(N에서 1을 뺀 횟수)만큼 더해준다.

그리고 N을 다시 target으로 갱신해주고 K로 나누어준다. 이때, N이 K보다 작을 경우(몫이 계속 0이 되므로) while문에서 빠져나온다.

그리고 N이 1이 되기까지 횟수이므로 (N-1)만큼 count에 더해주면 된다.(N을 더할 경우 N이 0이 되어버린다.)

728x90

'코테 > greedy' 카테고리의 다른 글

[Greedy] 백준 1041 주사위  (0) 2022.06.05
[Greedy] 숫자 카드 게임  (0) 2022.03.13
[Greedy] 큰 수의 법칙  (0) 2022.03.04
[Greedy] 거스름돈  (0) 2022.03.04
728x90

"이것이 코딩테스트다" 책 문제 _ greedy 책 문제

문제)

여러 개의 숫자 카드 중에서 가장 높은 숫자가 쓰인 카드 한 장을 뽑는 게임이다.

단, 게임의 룰을 지키며 카드를 뽑아야 하고 룰은 다음과 같다. 게임의 룰에 맞게 카드를 뽑는 프로그램을 만들어라.

 

   1. 숫자가 쓰인 카드들이 N * M 형태로 놓여 있다. 이때 N은 행의 개수를, M은 열의 개수를 의미한다.

   2. 먼저 뽑고자 하는 카드가 포함되어 있는 행을 선택한다.

   3. 그다음 선택된 행에 포함된 카드들 중 가장 숫자가 낮은 카드를 뽑아야 한다.

   4. 따라서 처음에 카드를 골라낼 행을 선택할 때, 이후에 해당 행에서 가장 숫자가 낮은 카드를 뽑을 것을 고려하여 최종적으로 가장 높은 숫자의 카드를 뽑을 수 있도록 전략을 세워야 한다.

 

입력조건

  • 첫째 줄에 숫자 카드들이 놓인 행의 개수 N과 열의 개수 M이 공백을 기준으로 하여 각가 자연수로 주어진다. (1 <= N, M <= 100)
  • 둘째 줄부터 N개의 줄에 걸쳐 각 카드에 적힌 숫자가 주어진다. 각 숫자는 1이상 10,000 이하의 자연수다.

 

출력조건

  • 첫째 줄에 게임의 룰에 맞게 선택한 카드에 적힌 숫자를 출력한다.
입력 예시1)
3 3
3 1 2
4 1 4
2 2 2
출력 예시1)
2
입력 예시2)
2 4
7 3 1 8
3 3 3 4
출력 예시2)
3

 

 

 

풀이)

각 행마다 가장 작은 수를 찾은 후 그 중에서 가장 큰 수를 출력하면 된다.

N, M = map(int, input().split())
minimum = []
for i in range(N):
    L = list(map(int, input().split()))
    minimum.append(min(L))
print(max(minimum))

N, M을 입력 받아서 정수로 변환해주고, 각 행에서 가장 작은 수를 저장할 minimum이라는 리스트를 생성한다.

행의 수만큼 반복하여 각 행을 입력받으면 L이라는 list로 받고, min()을 이용하여 가장 작은 수를 minimum에 추가한다.

모든 행의 작은 수를 추가한 이후, max()를 이용하여 가장 큰 수를 출력해주면 된다.

 

이 문제는 앞에서 나온 문제에 비하면 매우 쉬운 난이도고, 답에서 나온 풀이도 비슷하기 때문에 생략한다.

728x90

'코테 > greedy' 카테고리의 다른 글

[Greedy] 백준 1041 주사위  (0) 2022.06.05
[Greedy] 1이 될 때까지  (0) 2022.03.14
[Greedy] 큰 수의 법칙  (0) 2022.03.04
[Greedy] 거스름돈  (0) 2022.03.04

+ Recent posts