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

 

11725번: 트리의 부모 찾기

루트 없는 트리가 주어진다. 이때, 트리의 루트를 1이라고 정했을 때, 각 노드의 부모를 구하는 프로그램을 작성하시오.

www.acmicpc.net


풀이 과정

트리가 주어지고, 1번 노드가 루트라고 할 때 각 노드의 부모 노드 번호를 구하는 문제이다.

 

root 노드인 1번부터 시작해 BFS or DFS를 사용해서 트리를 탐색하고, 각 노드의 부모 노드를 갱신해주면 된다.


소스 코드

import sys
import collections

N = int(sys.stdin.readline())
graph = collections.defaultdict(list)
parent = collections.defaultdict(int)
Q = collections.deque([])
discovered = [False for _ in range(N+1)]

for _ in range(N-1):
    A, B = map(int, sys.stdin.readline().split())
    graph[A].append(B)
    graph[B].append(A)

Q.append(1)

while Q:
    cur = Q.popleft()
    for i in graph[cur]:
        if discovered[i]:
            continue
        parent[i] = cur
        discovered[i] = True
        Q.append(i)

for i in range(2, N+1):
    print(parent[i])

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

 

1916번: 최소비용 구하기

첫째 줄에 도시의 개수 N(1 ≤ N ≤ 1,000)이 주어지고 둘째 줄에는 버스의 개수 M(1 ≤ M ≤ 100,000)이 주어진다. 그리고 셋째 줄부터 M+2줄까지 다음과 같은 버스의 정보가 주어진다. 먼저 처음에는 그

www.acmicpc.net


풀이 과정

N개의 도시, M개의 버스가 주어지고 버스의 출발점과 도착지점, 그리고 드는 버스 비용이 주어질 때, A번째 도시에서 B번째 도시로 가는 경로의 최소 버스 비용을 구하는 문제이다.

 

https://greentea31.tistory.com/205

 

LeetCode - 743. Network Delay Time [Python]

https://leetcode.com/problems/network-delay-time/ Network Delay Time - LeetCode Level up your coding skills and quickly land a job. This is the best place to expand your knowledge and get prepared f..

greentea31.tistory.com

이 문제와 비슷한 조건의 문제이다. 똑같이 다익스트라 알고리즘을 구현해서 문제를 해결할 수 있다.

 


소스 코드

import sys
import heapq
import collections

N = int(sys.stdin.readline())
M = int(sys.stdin.readline())
graph = collections.defaultdict(list)
dist = collections.defaultdict(int)

for _ in range(M):
    depart, arrive, cost = map(int, sys.stdin.readline().split())
    graph[depart].append((cost, arrive))

start, end = map(int, sys.stdin.readline().split())

Q = [[0, start]]

while Q:
    cost, node = heapq.heappop(Q)
    if node not in dist:
        dist[node] = cost
        for w, v in graph[node]:
            temp = cost + w
            heapq.heappush(Q, [temp, v])

print(dist[end])

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

 

25559번: 패스

만약 모든 사람이 정확히 한 번 공을 받게 되는 상황이 발생할 수 없다면 $-1$을 출력한다. 그렇지 않다면, $N$개의 정수 $A_1, A_2, \ldots, A_N$을 공백으로 구분하여 출력한다. $A_i$는 $i$번째 게임에서

www.acmicpc.net


풀이 과정

원형으로 앉아있는 사람들 N명끼리 1 ~ N이 써져 있는 카드를 뽑고 버린 후, 뽑은 숫자만큼 공을 오른쪽으로 패스해서, 모든 사람들이 1번씩 공을 패스받았을 때 공이 이동한 순서를 출력하는 문제이다.

 

N번 카드를 뽑는 것은 공을 맨 처음 가지고 있는 1번 사람만이 가능하다. 1번 사람을 제외한 모든 사람은 공을 받으려면 일단 타인에게 패스를 받아야 하는데, N번 카드를 뽑으면 공이 한 바퀴 돌아서 자신에게 돌아오기 때문에 패스를 2번 받게 되어버리기 때문이다.

 

첫 번째 사람을 N번 카드를 뽑는다고 고정시키면, 나머지 카드는 1 ~ N-1이 남게 된다. 그런데 N이 홀수라면, 남은 카드의 합 (N(N-1) / 2) - N이 N의 배수가 되어 첫 번째 사람이 패스를 최소 1번 추가로 받게 된다. 따라서 N이 1을 제외한 홀수인 경우 모든 사람이 한 번씩만 패스를 받을 수는 없다.

 

N이 짝수인 경우 N, 1, N-2, 3, N-4, 5, N-6, 7 ... 순으로 카드를 뽑아서 패스할 경우 모든 사람이 한 번씩만 패스를 받을 수 있다. 다른 경우도 더 존재할 것 같지만 저런 케이스를 출력하여 문제를 해결하였다.


소스 코드

import sys

N = int(sys.stdin.readline())
if N == 1:
    print(1)
    exit(0)
if N % 2 == 1:
    print(-1)
    exit(0)

answer = []
left = N
right = 1
while(True):
    answer.append(str(left))
    left -= 2
    if len(answer) == N:
        break
    answer.append(str(right))
    right += 2
    if len(answer) == N:
        break

print(' '.join(answer))

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

 

25565번: 딸기와 토마토

즈티와 레오가 사는 집 앞마당에는 $N\times M$ 크기의 작은 텃밭이 있다. 텃밭의 좌측 상단의 좌표는 $(1, 1)$이며, 우측 하단의 좌표는 $(N, M)$이다. 텅 빈 텃밭이 허전해 보인 둘은 각자 원하는 작물

www.acmicpc.net


풀이 과정

직사각형 NxM 텃밭에 즈티가 가로 한 줄, 혹은 세로 한 줄을 지정해 임의의 연속한 K개의 딸기를 심고, 레오가 가로 한 줄, 혹은 세로 한 줄을 지정해 임의의 연속한 토마토 K개를 심는다. 씨앗의 종류에 상관 없이 씨앗이 심어진 영역의 좌표가 주어질 때, 딸기와 토마토가 모두 자라는 텃밭 영역의 칸 수와 해당 칸수를 출력하는 문제이다.

 

텃밭에서 씨앗이 심겨진 칸의 개수를 seed라 하자. 그렇다면 2K - seed의 값이 딸기와 토마토가 같이 심어진 칸의 수임을 쉽게 유추할 수 있을 것이다. 이 경우에 아래의 3가지 경우를 고려할 수 있다.

 

1. 2K == seed

이 경우에는 딸기와 토마토가 어떠한 영역에도 같이 심어지지 않았을 것이다. 같이 심어졌으려면 seed가 2K보다는 적어야 한다. 그냥 0을 출력해주면 된다.

 

1.5. K == 1

2K == seed가 아니면서 K == 1이면 board를 살펴보다가 1이 나오는 순간 그 지점의 좌표를 출력해주면 된다.

 

2. 2K - 1 == seed

딸기와 토마토가 같이 심겨진 영역이 한 칸만 존재하는 경우이다. 딸기를 심는 영역과 토마토를 심는 영역이 가로, 세로 직선이 교차하면서 생기는 경우가 있는데, 그 경우에는 같이 심기는 공간이 1칸만 존재할 수 있고, 2K - 1 == seed일때 이러한 상황이 발생할 수 있다. 따라서 2K - 1일때 모든 칸에 대해 현재 칸에 씨앗이 심겨져 있고, 가로로 왼쪽 혹은 오른쪽에 씨앗이 존재하면서 세로로 위쪽 혹은 아래쪽에 씨앗이 존재하는 경우에는 교차하면서 같이 심기는 경우로 판단하여 한 칸의 좌표만 출력해주었다.

 

3. 2K - 1 >= seed

seed가 2K - 1보다 작거나, 2K - 1 == seed 인데 가로 세로 직선이 교차하면서 같이 심기는게 아닌 경우가 있다. 이 때는 딸기 영역과 토마토 영역이 가로 직선 - 가로 직선이 겹치거나, 세로 직선 - 세로 직선이 겹쳐서 같이 심기는 영역이 발생하는 경우이다. board를 확인하면서 가로-가로, 세로-세로 겹침중 어느 것인지 판단 후, 겹친 갯수와 겹친 부분을 출력해주면 된다. 겹친 부분은 겹치기 시작한 부분 + seed - K부터 1씩 늘려가면서 2K-S개를 세주면 구할 수 있다. 왜 이렇게 되는지 모르겠다면 코드를 참고하고 그림을 그려가며 생각해보자.


소스 코드

import sys


def one_check(b, N, M):
    dx = [1, -1]
    dy = [1, -1]
    for y in range(N):
        for x in range(M):
            if board[y][x] == 0:
                continue
            check_x = False
            check_y = False
            for i in range(2):
                nx = x + dx[i]
                if 0 <= nx < M and board[y][nx] == 1:
                    check_x = True
                ny = y + dy[i]
                if 0 <= ny < N and board[ny][x] == 1:
                    check_y = True
            if check_x and check_y:
                return f'{y+1} {x+1}'

    return None


N, M, K = map(int, sys.stdin.readline().split())
board = []
for _ in range(N):
    board.append(list(map(int, sys.stdin.readline().split())))

seed = 0

for i in board:
    for j in i:
        if j == 1:
            seed += 1

if 2*K == seed:
    print(0)
    exit(0)

print(2*K - seed)

if K == 1:
    for y in range(N):
        for x in range(M):
            if board[y][x] == 1:
                print(f'{y+1} {x+1}') 
                exit(0)

if 2*K - 1 == seed:
    check = one_check(board, N, M)
    if check is not None:
        print(check)
        exit(0)

start_x, start_y = 2001, 2001
end_x, end_y = -1, -1

for y in range(N):
    for x in range(M):
        if board[y][x] == 1:
            start_x = min(x, start_x)
            start_y = min(y, start_y)
            end_x = max(x, end_x)
            end_y = max(y, end_y)

if start_x == end_x:
    for i in range(2*K - seed):
        print(f'{start_y + seed - K + i + 1} {start_x + 1}')
    exit(0)
if start_y == end_y:
    for i in range(2*K - seed):
        print(f'{start_y + 1} {start_x + seed - K + i + 1}')

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

 

25562번: 차의 개수

$1$ 이상 $10^9$ 이하의 서로 다른 정수 $N$개를 임의로 정하고 가능한 모든 쌍 $N(N-1)/2$개의 차를 구한다. 이때, 서로 다른 차의 개수의 최댓값과 최솟값을 구하고 각각 실례를 구성하여라.

www.acmicpc.net


풀이 과정

서로 다른 정수 N개의 모든 쌍의 차를 구할 때, 서로 다른 차의 개수의 최대값과 최소값을 구하는 문제이다.

 

모든 쌍의 개수는 NC2 = N(N-1) / 2 이고 NC2개의 모든 쌍의 차가 전부 다른 값을 가질 때 서로 다른 차의 개수가 최대가 될 것 같다. 이런 경우가 존재하는지 생각해보자.

 

특정 수의 배수로도 만들어보고, 소수들로만도 한번 해보고... 여러 숫자를 넣어가면서 규칙을 찾다보면 1, 2, 4, 8... 과 같은 등비수열에서 모든 쌍의 차가 다른 값을 가짐을 파악할 수 있다. 마침 문제에서 N도 최대 30으로 주었고, 2^30이 int의 최대값을 넘어가지 않으므로 2배씩 커지는 등비수열을 출력해주면 실례가 된다. 서로 다른 차의 개수의 최대값은 N(N-1) / 2, 실례는 공비를 2로 갖는 등비수열을 출력해주면 된다.

 

서로 다른 차의 개수가 최소가 되는 경우는 언제인가? 여러가지 수를 넣어보면서 규칙을 찾다 보면 1, 2, 3, 4... 나 2, 4, 6, 8... 과 같은 등차수열에서 서로 다른 차의 개수가 N-1개로 가장 적어보인다. 다른 숫자 쌍을 넣어봐도 N-1개 보다 줄어드는 경우는 나타나지 않는다. 따라서 서로 다른 차의 개수의 최소값은 N-1, 실례는 임의의 공차를 갖는 등차수열을 출력하면 문제가 풀릴 것 같다.

 

실제로 코드를 작성하니 문제가 해결되었다.


소스 코드

import sys

N = int(sys.stdin.readline())
print(N*(N-1) // 2)
number = 1
for _ in range(N):
    print(number, end=' ')
    number *= 2
print()
print(N-1)
number = 1
for _ in range(N):
    print(number, end=' ')
    number += 1

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

 

25558번: 내비게이션

1번 내비게이션이 안내한 경로는 $(0,0) \rightarrow (11,1) \rightarrow (9,9) \rightarrow (10,10)$으로, 총 거리는 $12 + 10 + 2 = 24$이다. 2번 내비게이션이 안내한 경로는 $(0,0) \rightarrow (1,12) \rightarrow (9,9) \ri

www.acmicpc.net


풀이 과정

시작점과 도착점, 그리고 각 내비게이션마다 방문해야 하는 중간점 정보를 담고 있을 때, 중간점을 모두 방문하고 도착점에 도착하는 거리가 가장 짧은, 가장 좋은 내비게이션이 무엇인지 구하는 문제이다.

 

그냥 문제가 시키는대로 구현하면 된다. 각 내비게이션마다 시작점 -> 중간점들 -> 도착점 경로의 맨해튼 거리를 모두 구해주고 그 중 가장 작은 거리를 안내하는 내비게이션의 번호를 출력하면 된다.


소스 코드

import sys


def manhatton(a, b, c, d):
    return abs(a-c) + abs(b-d)


N = int(sys.stdin.readline())
sx, sy, ex, ey = map(int, sys.stdin.readline().split())
answer = []
for _ in range(N):
    distance = 0
    now_x, now_y = sx, sy
    Mi = int(sys.stdin.readline())
    for _ in range(Mi):
        next_x, next_y = map(int, sys.stdin.readline().split())
        distance += manhatton(now_x, now_y, next_x, next_y)
        now_x, now_y = next_x, next_y
    distance += manhatton(now_x, now_y, ex, ey)
    answer.append(distance)

answer_index = 0
min_answer = min(answer)

for index, value in enumerate(answer):
    if value == min_answer:
        min_answer = value
        answer_index = index + 1

print(answer_index)

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

 

24542번: 튜터-튜티 관계의 수

첫째 줄에 튜터-튜티 관계를 정하는 경우의 수를 $1\,000\,000\,007$로 나눈 나머지를 출력한다.

www.acmicpc.net


풀이 과정

친분 관계 사이를 기반으로 튜터-튜티 지정이 가능하며, 교육 자료는 튜터 -> 튜티 방향으로 전달할 수 있다. 교육생간의 친분 관계가 포레스트인 그래프로 주어질 때 모든 교육생에게 자료가 전달되기 위해 찬솔이가 전해줘야 하는 인원수의 최소가 될 때의 튜터-튜티 관계를 정하는 경우의 수를 구하는 문제이다.

 

각 연결요소에 속해있는 정점의 개수를 정답 변수에 곱하는 방법으로 답을 구할 수 있다. 1 - 2 - 3, 4 - 5 - 6 - 7 - 8 이렇게 연결되어 있을 때의 경우는 3x5 = 15개의 경우의 수가 나올 것이다.


소스 코드

import sys
import collections


def bfs(x, visit, graph):
    q = collections.deque([x])
    visit[x] = True
    number = 1

    while q:
        cur = q.popleft()
        for nxt in graph[cur]:
            if visit[nxt]:
                continue
            q.append(nxt)
            visit[nxt] = True
            number += 1

    return number


graph = collections.defaultdict(list)
N, M = map(int, sys.stdin.readline().split())
visit = [False for _ in range(N+1)]
answer = 1
mod = 1000000007

for _ in range(M):
    u, v = map(int, sys.stdin.readline().split())
    graph[u].append(v)
    graph[v].append(u)

for v in range(1, N+1):
    if not visit[v]:
        answer *= bfs(v, visit, graph)
        answer %= mod

print(answer)

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

 

10026번: 적록색약

적록색약은 빨간색과 초록색의 차이를 거의 느끼지 못한다. 따라서, 적록색약인 사람이 보는 그림은 아닌 사람이 보는 그림과는 좀 다를 수 있다. 크기가 N×N인 그리드의 각 칸에 R(빨강), G(초록)

www.acmicpc.net


풀이 과정

격자 칸의 그림에 같은 색으로 이루어진 구역의 수를 구하되, 적록색약인 (적색과 녹색 구분 불가)사람과 적록색약이 아닌 사람이 보는 구역의 수를 각각 구하라는 문제이다.

 

BFS로 연결 요소의 수를 한 번 구하고, 모든 녹색을 적색으로 혹은 모든 적색을 녹색으로 바꿔서 색깔을 구분 못하게 한 뒤, BFS로 연결 요소의 수를 한 번 더 구해주면 된다.


소스 코드

#include <iostream>
#include <queue>
using namespace std;
char board[101][101];
bool visit[101][101];
int dy[4] = {0, 1, 0, -1};
int dx[4] = {1, 0, -1, 0};
int N;

void bfs(int y, int x) {
    queue<pair<int, int>> Q;
    visit[y][x] = true;
    Q.push(make_pair(y, x));

    while(!Q.empty()) {
        auto cur = Q.front(); Q.pop();
        for (int i = 0; i < 4; i++) {
            int ny = cur.first + dy[i];
            int nx = cur.second + dx[i];
            
            if (0 <= ny && ny < N && 0 <= nx && nx < N) {
                if (board[ny][nx] != board[y][x]) continue;
                if (visit[ny][nx]) continue;
                visit[ny][nx] = true;
                Q.push(make_pair(ny, nx));
            }
        }
    }

}

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);

    cin >> N;
    int answer = 0;
    int answer2 = 0;

    for (int i = 0; i < N; i++) {
        for (int j = 0; j < N; j++) {
            cin >> board[i][j];
        }
    }

    for (int i = 0; i < N; i++) {
        for (int j = 0; j < N; j++) {
            if (visit[i][j]) continue;
            bfs(i, j);
            answer++;
        }
    }

    for (int i = 0; i < N; i++) {
        for (int j = 0; j < N; j++) {
            visit[i][j] = false;
            if (board[i][j] == 'G') board[i][j] = 'R';
        }
    }

    for (int i = 0; i < N; i++) {
        for (int j = 0; j < N; j++) {
            if (visit[i][j]) continue;
            bfs(i, j);
            answer2++;
        }
    }

    cout << answer << ' ' << answer2;

    return 0;
}

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

 

1012번: 유기농 배추

차세대 영농인 한나는 강원도 고랭지에서 유기농 배추를 재배하기로 하였다. 농약을 쓰지 않고 배추를 재배하려면 배추를 해충으로부터 보호하는 것이 중요하기 때문에, 한나는 해충 방지에 

www.acmicpc.net


풀이 과정

상하좌우 배추에 배추흰지렁이가 옮겨서 해충으로 부터 보호할 수 있을 때, 격자 모양의 밭의 모든 배추를 보호하려면 배추흰지렁이가 몇 마리 필요한지 구하는 문제이다.

 

연결 요소의 개수를 구하라는 문제와 같다. flood-fill을 bfs로 구현하고 미방문 배추를 bfs로 방문해주면서 연결 요소의 개수를 세주면 된다.


소스 코드

#include <iostream>
#include <queue>
using namespace std;
bool board[51][51];
bool visit[51][51];
int dy[4] = {0, 1, 0, -1};
int dx[4] = {1, 0, -1, 0};
int M, N, K;

void bfs(int y, int x) {
    queue<pair<int, int>> Q;
    visit[y][x] = true;
    Q.push(make_pair(y, x));

    while(!Q.empty()) {
        auto cur = Q.front(); Q.pop();
        for (int i = 0; i < 4; i++) {
            int ny = cur.first + dy[i];
            int nx = cur.second + dx[i];

            if (0 <= ny && ny < N && 0 <= nx && nx < M) {
                if (!board[ny][nx]) continue;
                if (visit[ny][nx]) continue;
                visit[ny][nx] = true;
                Q.push(make_pair(ny, nx));
            }
        }
    }
}

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);

    int T;
    cin >> T;
    while(T--) {
        cin >> M >> N >> K;
        int Y, X;
        int answer = 0;

        for (int i = 0; i < K; i++) {
            cin >> X >> Y;
            board[Y][X] = true;
        }

        for (int i = 0 ; i < N; i++) {
            for (int j = 0; j < M; j++) {
                if (board[i][j] && !visit[i][j]) {
                    answer++;
                    bfs(i, j);
                }
            }
        }

        cout << answer << '\n';


        for (int i = 0; i < 51; i++) {
            for (int j = 0; j < 51; j++) {
                board[i][j] = false;
                visit[i][j] = false;
            }
        }
    }

    return 0;
}

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

 

1697번: 숨바꼭질

수빈이는 동생과 숨바꼭질을 하고 있다. 수빈이는 현재 점 N(0 ≤ N ≤ 100,000)에 있고, 동생은 점 K(0 ≤ K ≤ 100,000)에 있다. 수빈이는 걷거나 순간이동을 할 수 있다. 만약, 수빈이의 위치가 X일

www.acmicpc.net


풀이 과정

현재 N에 있고, 동생이 K에 있을 때, 하루마다 현재 점에서 +1, -1, *2로 이동이 가능한데, 동생을 찾는 가장 빠른 시간을 구하는 문제이다.

 

BFS로 +1, -1, *2 이동해보면서 원점으로 부터의 거리를 계산하고, K일때 원점에서의 거리를 출력해주면 된다. 동생이 10만까지만 위치 가능하긴 해도, 수빈이는 10만을 넘어선 점에 위치가 가능하긴 한데 이 문제에서는 10만을 넘어가면 무조건 원점과 10만까지의 거리보다 더 많은 거리를 이동해야 하므로 고려해주지 않아도 된다.


소스 코드

#include <iostream>
#include <queue>
using namespace std;

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);

    int d[100001];

    for (int &i : d) {
        i = -1;
    }

    queue<int> Q;

    int N, K;
    cin >> N >> K;

    d[N] = 0;
    Q.push(N);

    while(!Q.empty()) {
        int cur = Q.front(); Q.pop();
        if (cur == K) {
            cout << d[K];
            return 0;
        }

        for (int next : {cur-1, cur+1, 2*cur}) {
            if (next < 0 || next > 100000) continue;
            if (d[next] != -1) continue;
            d[next] = d[cur] + 1;
            Q.push(next);
        }
    }

    return 0;
}

'알고리즘 문제 풀이 > 백준' 카테고리의 다른 글

백준 10026 - 적록색약 [C++]  (0) 2022.08.01
백준 1012 - 유기농 배추 [C++]  (0) 2022.08.01
백준 4179 - 불 [C++]  (0) 2022.08.01
백준 7576 - 토마토 [C++]  (0) 2022.08.01
백준 2504 - 괄호의 값 [C++]  (0) 2022.07.31

+ Recent posts