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

 

1260번: DFS와 BFS

첫째 줄에 정점의 개수 N(1 ≤ N ≤ 1,000), 간선의 개수 M(1 ≤ M ≤ 10,000), 탐색을 시작할 정점의 번호 V가 주어진다. 다음 M개의 줄에는 간선이 연결하는 두 정점의 번호가 주어진다. 어떤 두 정점 사

www.acmicpc.net


문제 해결을 위한 과정

이 문제의 경우 제가 전에 포스팅했던 DFS https://bgspro.tistory.com/14?category=981927,                                 BFS https://bgspro.tistory.com/15?category=981927를 정확하게 숙지 및 암기하고 있다면 실버 2 티어와 정답률 33프로의 문제임에도 불구하고 굉장히 쉽게 해결할 수 있는 문제입니다. 먼저 문제를 보겠습니다. 문제에서 그래프가 주어지고 이를 DFS로 탐색하는 경우 그리고 BFS로 탐색하는 경우를 출력하면 정답 판정을 받을 수 있습니다.

dfs와 bfs는 위의 링크를 각각 참고하면 되겠습니다.


문제 해결을 위한 팁

문제를 보면 노드들이 양방향으로 연결이 되어있는것을 알 수 있습니다. 따라서 각각의 그래프를 연결할 때 양방향으로 연결을 해야 합니다. 또한 노드가 여러 노드와 연결이 되어있다면 그중 번호가 낮은 것을 우선하여 탐색하므로 입력을 해 준 뒤 각각의 행에 오름차순으로 정렬을 해줘야 합니다.


소스코드

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
from collections import deque
 
n, m, v = map(int, input().split())
graph = [[] for _ in range(1+n)]
visited = [0* (1+n)
 
for i in range(m):
  a, b = map(int, input().split())
  # 양방향 연결
  graph[a].append(b)
  graph[b].append(a)
 
for i in range(n+1):
  graph[i].sort() # 연결된 노드가 여러곳일 경우 낮은 숫자를 가진 노드부터 탐색하기 위해 오름차순으로 
 
def dfs(graph, visited, v):
  print(v, end=" ")
  visited[v] = 1
  for i in graph[v]:
    if not visited[i]:
      dfs(graph, visited, i)
 
def bfs(graph, visited, start):
  q = deque()
  q.append(start)
  visited[start] = 1
  while q:
    v = q.popleft()
    print(v, end= " ")
    for i in graph[v]:
      if not visited[i]:
        q.append(i)
        visited[i] = 1
 
dfs(graph, visited, v)
visited = [0* (1+n)
print()
bfs(graph, visited, v)
 
cs

소스코드 - c++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#include <bits/stdc++.h>
#define MAX 1001
using namespace std;
 
vector<int> graph[MAX];
bool visited[MAX]; // false 초기화
bool visited2[MAX];
 
void dfs(int x) {
    visited[x] = true;
    printf("%d ", x);
 
    for (int i = 0; i < graph[x].size(); i++) {
        int y = graph[x][i];
        if (!visited[y]) {
            dfs(y);
        }
    }
}
 
void bfs(int start) {
    queue<int> q;
    q.push(start);
    visited2[start] = true;
 
    while (!q.empty()) {
        int x = q.front();
        printf("%d ", x);
        q.pop();
        for (int i = 0; i < graph[x].size(); i++) {
            int y = graph[x][i];
            if (!visited2[y]) {
                q.push(y);
                visited2[y] = true;
            }
        }
    }
}
 
int main(void) {
    int n, m, v;
    scanf("%d %d %d"&n, &m, &v);
 
    for (int i = 1; i < m + 1; i++) {
        int a, b;
        scanf("%d %d"&a, &b);
        graph[a].push_back(b);
        graph[b].push_back(a);
    }
 
    for (int i = 1; i < n + 1; i++) { // 정렬
        sort(graph[i].begin(), graph[i].end());
    }
 
    dfs(v);
    printf("\n");
    bfs(v);
    return 0;
}
cs

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

 

2810번: 컵홀더

첫째 줄에 좌석의 수 N이 주어진다. (1 ≤ N ≤ 50) 둘째 줄에는 좌석의 정보가 주어진다.

www.acmicpc.net


문제 해결을 위한 과정

이 문제는 그리디 알고리즘으로 쉽게 해결할 수 있는 문제였습니다. 먼저 그림과 함께 예시를 보도록 하겠습니다.

1) 일반적인 경우

예시를 그림으로 표현하면 위의 그림과 같은데 먼저 좌측부터 채워나간다고 하겠습니다. 이렇게 하면 마지막 커플석의 경우 좌측 우측 컵홀더를 이용할 수 있고 사용하지 못하는 사람은 2번째 커플석에서 1명, 3번째 커플석에서 1명

총 2명이 됩니다. 이를 확장하면 존재하는 커플석 -1 의 사람 수만큼 컵홀더를 사용할 수 없습니다. 따라서 입력받은 컵홀더의 수 - 1이 정답이 됩니다.

 

2) 예외의 경우

예외의 경우가 한가지 존재하는데 바로 전체다 S인 경우입니다. 이 경우는 커플석이 존재하지 않으므로 위의 

커플석 - 1로는 해결 할 수 없습니다. 이 경우는 일반 좌석의 개수보다 컵홀더가 하나 더 많기 때문에 일반석 모두 컵홀더를 사용할 수 있습니다. 따라서 이 경우 입력받은 S의 수를 그대로 출력합니다.


소스코드
1
2
3
4
5
6
7
8
9
10
11
12
= int(input())
data = input()
count = 0
for i in range(len(data)):
  if data[i] == 'L':  
    count += 1
 
if count == 0# 커플석이 없는 경우
  print(n)
else:
  print(n-(count//2-1))
 
cs

 

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

 

13305번: 주유소

표준 입력으로 다음 정보가 주어진다. 첫 번째 줄에는 도시의 개수를 나타내는 정수 N(2 ≤ N ≤ 100,000)이 주어진다. 다음 줄에는 인접한 두 도시를 연결하는 도로의 길이가 제일 왼쪽 도로부터 N-1

www.acmicpc.net


문제 해결을 위한 과정

이 문제의 경우 그리디 알고리즘으로 해결할 수 있는 문제입니다. 그리디 알고리즘의 개념만 정확히 알고 있다면 쉽게 풀 수 있는 문제입니다. 가장 최선의 경우를 선택하는 경우 이기 때문입니다. 먼저 문제를 예를 들어봅시다. 

 

맨 처음 비용을 5로 잡았을때 다음 비용은 2 이므로 (5 < 2) 이 구간의 거리 즉 2만큼은 5라는 비용으로 이동합니다. 그 후 비용을 2로 갱신해줍니다.

5 * 2 = 10

 

비용을 2로 잡은 후 다음 비용은 4 이므로 (2 < 4) 이므로 다음 비용까지 비용 2를 유지합니다. 다음 비용은 1 이므로 갱신해 줍니다. 즉 3 + 1의 구간은 2라는 비용으로 이동합니다. 

2 * (3 + 1) = 8

 

비용은 1 이지만 마지막 구간이므로 종결합니다.

따라서 답은 10 + 8로 최소는 18입니다


소스코드

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
= int(input())
route = list(map(int, input().split()))
amount = list(map(int, input().split()))
 
price = amount[0]
ans = 0
= 1
ro = route[0]
while True:
  if i == n-1:
    ans += price * ro
    break
  if price < amount[i]:
    ro += route[i]
  else:
    ans += price * ro
    price = amount[i]
    ro = route[i]
  i += 1
 
print(ans)
cs

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

 

1715번: 카드 정렬하기

정렬된 두 묶음의 숫자 카드가 있다고 하자. 각 묶음의 카드의 수를 A, B라 하면 보통 두 묶음을 합쳐서 하나로 만드는 데에는 A+B 번의 비교를 해야 한다. 이를테면, 20장의 숫자 카드 묶음과 30장

www.acmicpc.net


문제 해결을 위한 과정

이 문제의 경우 잘 못 생각하기가 쉬운 문제였던 것 같습니다. 저도 처음에 그냥 문제를 해결하려 하였다가 틀렸었고 백준 사이트에 질문게시판을 보고 접근방식이 잘못되었다는 것을 알게 된 후 해결할 수 있었던 문제였습니다.

먼저 heap을 이용해야 합니다. 파이썬의 경우 최소 힙 형태로 구현이 되어있기 때문에 보다 쉽게 해결할 수 있었습니다. 예시를 그림과 같이 보겠습니다.

(원래 heap은 트리의 형태로 구현되지만 시인성을 위해 큐의 형태로 그림을 표현하였습니다.)

 

1. 각 원소들을 heapq에 넣어준다.

10 20 40

 

2. heapq에서 원소 두개를 빼준후 더한다.

10 + 20 = 30

30

 

3. 합한 값을 heapq에 넣어준다

30 40

 

4. heapq에서 원소 두개를 빼준 후 더한다.

30 + 40 = 70

None

 

5. 2번에서 구한 30 과 4번에서 더한 70을 더해 100을 만든다.


소스코드

 

1
2
3
4
5
6
7
8
9
10
11
12
13
import heapq
= []
= int(input())
for i in range(N):
  heapq.heappush(q, (int(input())))
 
sum = 0
while len(q) > 1:
  temp1 = heapq.heappop(q)
  temp2 = heapq.heappop(q)
  heapq.heappush(q, (temp1+temp2))
  sum += temp1+temp2
print(sum)
cs

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

 

2437번: 저울

하나의 양팔 저울을 이용하여 물건의 무게를 측정하려고 한다. 이 저울의 양 팔의 끝에는 물건이나 추를 올려놓는 접시가 달려 있고, 양팔의 길이는 같다. 또한, 저울의 한쪽에는 저울추들만 놓

www.acmicpc.net


문제 해결을 위한 과정

이 문제의 경우 골드 3 티어 문제로 저는 굉장히 어렵게 풀었던 문제입니다. 그리디 알고리즘으로 해결할 수 있는 문제인데 우선 알아야 하는 것이 있습니다. 바로 1부터 X - 1까지 만들 수 있는 금액이라고 가정을 했을 때 X가 새로 들어온 화폐단위인 a[i]보다 크다면 X원은 만들 수 없다는 것입니다. 이 경우는 저는 암기를 하기로 결정하였습니다. 크루스칼 알고리즘도 그리디이긴 하지만 암기가 필요한 부분입니다. 따라서 해당하는 경우도 암기를 바탕으로 해결합시다.


문제 해결을 위한 팁

팁까지는 아니지만 꼭 짚고 넘어가야할 조건이 있습니다. 바로 리스트가 정렬이 된 상태이어야만 한다는 것입니다.


소스코드

 

1
2
3
4
5
6
7
8
9
10
11
= int(input())
data = list(map(int, input().split()))
data.sort()
 
target = 1
for x in data:
  if target < x:
    break
  target += x
 
print(target)
cs

 

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

 

18353번: 병사 배치하기

첫째 줄에 N이 주어진다. (1 ≤ N ≤ 2,000) 둘째 줄에 각 병사의 전투력이 공백을 기준으로 구분되어 차례대로 주어진다. 각 병사의 전투력은 10,000,000보다 작거나 같은 자연수이다.

www.acmicpc.net


문제 해결을 위한 과정

이 문제의 경우 가장 긴 증가하는 부분 수열  알고리즘을 알고 있다면 쉽게 해결할 수 있는 문제입니다. 해당 알고리즘에 대해서는 포스팅을 해 놓았습니다. 링크는 다음과 같습니다. https://bgspro.tistory.com/33?category=981927

 

가장 긴 증가하는 부분 수열 - Longest Increasing Subsequence (Python)

개념 가장 긴 증가하는 부분 수열 다시 말하면 LIS라고도 하는 이것은 다이나믹 프로그래밍 기법 중에 하나입니다. 말 그대로 어떤 수열이 주어졌을 때 해당하는 수열에서 오름차순 혹은 내림차

bgspro.tistory.com

먼저 문제의 경우 내림차순으로 배치를 하고자 한다고 합니다. 그러나 가장 긴 증가하는 부분 수열의 경우 오름차순에 대해서 하는 경우가 좀 더 일반적입니다. 따라서 입력받은 리스트를 reverse 함수를 이용해서 역순으로 바꾼 후 LIS 알고리즘을 사용하면 됩니다.


문제 해결을 위한 팁

LIS 알고리즘을 사용할 때 이중 for문을 통해 해결하는데 바깥 for문은 1번째 원소부터 n번째 원소까지, 안쪽 for문은 0번째 원소부터 바깥 for문의 인덱스까지 조회하는 방식으로 해결합니다.


소스코드

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
= int(input())
data = [0]
ans = [0]*(2+n)
for i in range(1, n+1):
  t, p = map(int, input().split())
  data.append((i, t, p))
 
for i in range(1, n+1):
  day, t, p = data[i]
  if day + t <= n+1:
    ans[i] += p
    for j in range(day+t, n+1):
      ans[j] = max(ans[day], ans[j])
 
print(max(ans))
 
cs

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

 

14501번: 퇴사

첫째 줄에 백준이가 얻을 수 있는 최대 이익을 출력한다.

www.acmicpc.net


문제 해결을 위한 과정

이 문제는 전형적인 다이나믹 프로그래밍 문제 중에 하나입니다. 예시를 기준으로 1일부터 7일까지의 T, P 값을 이용하여 문제를 해결하면 됩니다. 예시를 기준으로 설명을 하겠습니다.

 

1일까지 최대한 많은 금액을 받을수 있는 일정은 1일째만 일하는 10원입니다. 

2일까지 최대한 많은 금액을 받을 수 있는 일정은 2일째만 일하는 20원 입니다.

3일까지 최대한 많은 금액을 받을 수 있는 일정은 2일째만 일하는 20원입니다.

4일까지 최대한 많은 금액을 받을 수 있는 일정은 1일째, 4일째 일하는 30원입니다.

5일까지 최대한 많은 금액을 받을 수 있는 일정은 1일째, 4일째, 5일째 일하는 45원입니다.

6일까지 최대한 많은 금액을 받을 수 있는 일정은 1일째, 4일째, 5일째 일하는 45원입니다.

7일까지 최대한 많은 금액을 받을 수 있는 일정은 1일째, 4일째, 5일째 일하는 45원입니다.

 

따라서 우리는 먼저 0으로 전부 초기화 한 dp라는 리스트를 생성한 후 해당하는 날짜와 해당 날짜에서 T만큼 지난날을 P로 초기화를 해주면 됩니다. 예시는 다음과 같습니다.

 

먼저 전체가 0으로 된 리스트를 생성합니다.

0 0 0 0 0 0 0

 

1일째 일을 하면 4일째부터 일을 할 수 있으므로 1일에 P를 더해주고 4일째부터는 1일째의 dp값과 해당 날짜의 dp값의 max값을 넣어준다.

10 0 0 10 10 10 10

 

2일째 일을 하면 7일째부터 일을 할 수 있으므로 2일에 P를 더해주고 7일째부터는 2일째의 dp값과 해당 날짜의 dp값의 max값을 넣어준다.

10 20 0 10 10 10 20

 

3일째 일을 하면 4일째부터 일을 할 수 있으므로 3일에 P를 더해주고 4일째부터는 3일째의 dp값과 해당 날짜의 dp값의 max값을 넣어준다.

10 20 10 10 10 10 20

 

4일째 일을 하면 5일째부터 일을 할 수 있으므로 4일에 P를 더해주고5일째부터는 4일째의 dp값과 해당 날짜의 dp값의 max값을 넣어준다.

10 20 10 30 30 30 30

 

5일째 일을 하면 7일째부터 일을 할 수 있으므로 5일에 P를 더해주고7일째부터는 5일째의 dp값과 해당 날짜의 dp값의 max값을 넣어준다.

10 20 10 30 45 30 45

그 뒤로 6일째와 7일째는 일이 끝나는 날이 N을 벗어나므로 고려하지 않는다.

백준이가 얻을 수 있는 최대 수익은 dp리스트의 max값인 45이다.


소스코드

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
= int(input())
data = [0]
ans = [0]*(2+n)
for i in range(1, n+1):
  t, p = map(int, input().split())
  data.append((i, t, p))
 
for i in range(1, n+1):
  day, t, p = data[i]
  if day + t <= n+1:
    ans[i] += p
    for j in range(day+t, n+1):
      ans[j] = max(ans[day], ans[j])
 
print(max(ans))
 
cs

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

 

1932번: 정수 삼각형

첫째 줄에 삼각형의 크기 n(1 ≤ n ≤ 500)이 주어지고, 둘째 줄부터 n+1번째 줄까지 정수 삼각형이 주어진다.

www.acmicpc.net

 


문제 해결을 위한 과정

전형적인 다이나믹 프로그래밍 문제였습니다. 이 문제의 경우 숫자의 배열이 삼각형이라는 점이 존재하는데 이를 다음의 표처럼 입력받은 부분을 제외한 영역을 0을 채워주면 보다 쉽게 해결할 수 있습니다. 이 과정을 통해 0번째 열의 경우는 바로 위에 존재하는 숫자를 더해주면 되고 그 외의 경우는 위 행의 좌측 열 값과 위 행의 동일 열 값의 max값을 더해주는 과정을 반복해주면 쉽게 해결할 수 있습니다. 이를 점화식으로 표현하면 다음과 같습니다.

 

array[i][j] += max(array[i-1][j-1], array[i-1][j]) 

(단 열이 0번째가 아닌 경우)

 

1. 입력받은 곳을 제외하고 0으로 채운 상태

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

 

2. 적색 숫자는 0번째 열 이므로 위의 7을 그대로 더함, 청색 숫자는 좌측 위의 7과 위의 0중 최댓값인 7을 더함

7 0 0 0 0
10 15 0 0 0
8 1 0 0 0
2 7 4 4 0
4 5 2 6 5

 

3. 적색 숫자는 0번째 열 이므로 위의 10을 그대로 더함. 청색 숫자는 좌측 위의 숫자와 위의 숫자의 최댓값인 각각 15, 15를 더함

0 0 0 0
10 15 0 0 0
18 16 15 0 0
7 4 4 0
4 5 2 6 5

 

4. 적색 숫자는 0번째 열 이므로 위의 18을 그대로 더함, 청색 숫자는 좌측 위의 숫자와 위의 숫자의 최댓값인 각각 18, 16, 15를 더함

7 0 0 0 0
10 15 0 0 0
18 16 15 0 0
20 25 20 19 0
4 5 2 6 5

 

5.  적색 숫자는 0번째 열 이므로 위의 20을 그대로 더함. 청색 숫자는 좌측 위의 숫자와 위의 숫자의 최댓값인 각각 25, 25, 20, 19를 더함

7 0 0 0 0
10 15 0 0 0
18 16 15 0 0
20 25 20 19 0
24 30 27 26 24

소스코드
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
= int(input())
array = [[0* n for _ in range(n)] # 0으로 전부 채워진 이차원 배열 생성
for i in range(n):
  input_data = list(map(int, input().split()))
  for j in range(len(input_data)):
    array[i][j] = input_data[j]
 
for i in range(1, n):
  for j in range(n):
    if j == 0# 0번째 열 인경우 
      array[i][j] += array[i-1][j]
    else# 그 외의 
      array[i][j] += max(array[i-1][j-1], array[i-1][j])
 
answer = 0
for i in range(n):
  answer = max(answer, array[n-1][i])
print(answer)        
cs

 

 

+ Recent posts