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

 

1711번: 직각삼각형

첫째 줄에 점의 개수 N(3 ≤ N ≤ 1,500)이 주어진다. 둘째 줄부터 N개의 줄에 걸쳐 각 점의 x좌표와 y좌표가 빈 칸을 사이에 두고 주어진다. 좌표값은 절댓값이 1,000,000,000을 넘지 않는 정수이며, 주

www.acmicpc.net

브루트포스로 접근한 문제다.

 

풀이

들어오는 좌표 중 3개를 선택하는 조합 반복문을 생성. 피타고라스의 정리를 사용해 직각 삼각형인지 판별하면 된다.

단 해당 문제에서 흥미로웠던 점은 세 점 A, B, C의 조합에서 나온 3가지의 선분(AB, BC, AC) 중 가장 긴 선분을 찾아내는 부분에서 시간초과가 났다.

 

처음에는 단순히 3개의 선분의 길이를 배열에 담아낸 뒤 내림차순 정렬하여 (0번 원소 == 1번 원소 + 2번 원소) 조건문으로 판별하였으나, 시간초과가 발생. 

func isRightTriangle(a:(Int,Int),b:(Int,Int),c:(Int,Int)) -> Bool{
    let AB = ((a.0-b.0)*(a.0-b.0)) + ((a.1-b.1)*(a.1-b.1))
    let AC = ((a.0-c.0)*(a.0-c.0)) + ((a.1-c.1)*(a.1-c.1))
    let BC = ((b.0-c.0)*(b.0-c.0)) + ((b.1-c.1)*(b.1-c.1))
    
    let tmp = [AB,AC,BC].sorted(by: >)
    return tmp[0]==tmp[1]+tmp[2] ? true:false
}

 

이때부터 조금 헤맸다. 시간복잡도를 계산해 보면 입력좌표는 최대 1500개가 입력. 1500C3 = 561,375,500 여기서 각 조합마다 정렬이 이루어지는데, Swift 배열의 정렬 함수 시간복잡도는 0(N)이므로 대략 16억 번의 수행이 이루어진다. 보통 알고리즘 문제를 풀 때 러프하게 1초당 1억 번의 연산으로 계산하게 되는데, 5초의 시간은 턱없이 부족한 시간인 것이다.

 

그러다 문득 배열을 생성하고 정렬하는 것보단 비트연산이 더욱 빠르겠다는 생각이 들어 아래와 같이 수정하였더니 통과하였다.

func isRightTriangle(a:(Int,Int),b:(Int,Int),c:(Int,Int)) -> Bool{
    let AB = ((a.0-b.0)*(a.0-b.0)) + ((a.1-b.1)*(a.1-b.1))
    let AC = ((a.0-c.0)*(a.0-c.0)) + ((a.1-c.1)*(a.1-c.1))
    let BC = ((b.0-c.0)*(b.0-c.0)) + ((b.1-c.1)*(b.1-c.1))

//  let tmp = [AB,AC,BC].sorted(by: >)
//  return tmp[0]==tmp[1]+tmp[2] ? true:false

    let res = (AB==AC+BC) || (AC == AB+BC) || (BC==AB+AC)
    return res ? true:false
}

 

정답 코드

'Problem Solving > BOJ' 카테고리의 다른 글

[14719] 빗물  (0) 2023.06.02
[5719] 거의 최단 경로  (0) 2023.04.30
[16169] 수행시간  (0) 2023.04.11
[24526] 전화 돌리기  (0) 2023.04.05
[14907] 프로젝트 스케줄링  (0) 2023.04.03

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

 

16169번: 수행 시간

첫 번째 줄에는 컴퓨터의 개수 n이 주어진다. (3 ≤ n ≤ 100) 두 번째 줄부터 n개의 줄에 걸쳐 1번부터 n번까지 각 컴퓨터의 계급과 동작 속도 t가 공백을 두고 주어진다. (1 ≤ t ≤ 100)

www.acmicpc.net

위상정렬로 접근한 문제다.

 

풀이

해당 문제의 컴퓨터는 자료를 전송할 다음 등급의 컴퓨터가 여러 대라면 동시에 자료를 전송하는 것으로 계산하면 된다. 즉 위상정렬을 통해 다음 등급의 컴퓨터를 탐색할 때, 간선의 비용이 최대 값인 경우만 찾아내면 된다.

 

입력되는 등급을 통해 위상정렬 순서를 구해 탐색을 수행한다. (다음 등급의 컴퓨터에게 자료를 전달하는 시간 + 다음 컴퓨터의 구동시간)의 최댓값을 저장할 ans 배열을 생성. 매 탐색마다 해당 배열을 최댓값으로 갱신하고 탐색이 종료된 후 ans 배열의 최댓값을 출력하면 정답이다.

 

예제를 기준으로 다음과 같이 수행된다.

가장 먼저 가장 낮은 등급의 컴퓨터인 1번과 7번 컴퓨터가 동작한다.

각자의 (동작시간 + 전송시간)의 값 중 가장 큰 값이 다음 등급인 6번 컴퓨터에게 전달되며,

해당 컴퓨터는 자신의 구동시간을 더해 ans배열에 갱신한다.

이후 탐색 큐에 6과 ans [6]의 값 36을 담아 다음 탐색을 수행한다.

2등급 컴퓨터인 6번 노드는 다음 등급의 컴퓨터인 2번과 3번 컴퓨터에 자료를 전송.

6번 컴퓨터의 대기시간 + 동작시간의 값 + 전송시간의 값이 전달된다.

이제 해당 값에 2번과 3번 컴퓨터의 구동시간을 더해 ans배열을 갱신한다.

각 노드로 진입하는 대기시간 + 구동시간 + 전송시간의 값 중 가장 큰 값을 입력받아 ans배열을 갱신해 나가면 된다.

구동시간에는 음수가 입력되지 않으므로 마지막 컴퓨터의 대기시간 + 구동시간 + 동작시간을 더해 출력하면 된다.

 

정답 코드

'Problem Solving > BOJ' 카테고리의 다른 글

[5719] 거의 최단 경로  (0) 2023.04.30
[1711] 직각삼각형  (0) 2023.04.19
[24526] 전화 돌리기  (0) 2023.04.05
[14907] 프로젝트 스케줄링  (0) 2023.04.03
[2637] 장난감 조립  (0) 2023.04.01

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

 

24526번: 전화 돌리기

첫 줄에 부원의 수 $N$과 관계의 수 $M$이 공백을 사이에 두고 정수로 주어진다. ($2 \le N \le 100,000$ , $1 \le M \le $ $500,000$) 둘째 줄부터 $M+1$번째 줄까지 어떤 부원 $U_{i}$가 전화를 받았을 때 다른 부원

www.acmicpc.net

위상정렬 문제다.

 

풀이

사이클이 생기는 노드, 그리고 해당 노드로 진입하는 노드를 제외한 나머지 노드의 수를 출력하는 문제다. 

주어지는 간선의 방향을 반대로 저장하고 위상정렬을 통해 탐색한다면, 정답을 구할 수 있다. 이유는 위상정렬의 필수조건인 indegree가 0인 노드를 큐에 담아 탐색하는 부분에서 찾을 수 있다. 사이클이 발생한다는 것은 곧 indegree가 0이 되지 않는다는 이야기이기에 역방향으로 탐색하게 되면 사이클은 큐에 담기지 않게 된다.

 

예제의 경우를 그래프로 그려보면 좌측과 같다. 위상정렬을 통해 탐색을 시작하면 1부터 시작하기에 처음부터 사이클이 일어날지 알 수 없다. 반면 우측의 경우처럼 역방향으로 그래프를 그리면 4와 6만 큐에 담긴 채 사이클이 일어나는 3번 노드는 큐에 담기지 않게 되고 그대로 탐색이 종료된다. 따라서 정답은 4, 6번 학생인 두 명의 부원이라는 정답을 출력할 수 있다.

 

정답 코드

'Problem Solving > BOJ' 카테고리의 다른 글

[1711] 직각삼각형  (0) 2023.04.19
[16169] 수행시간  (0) 2023.04.11
[14907] 프로젝트 스케줄링  (0) 2023.04.03
[2637] 장난감 조립  (0) 2023.04.01
[13334] 철로  (0) 2023.03.26

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

 

14907번: 프로젝트 스케줄링

입력은 1줄에서 26줄까지 입력될 수 있으며, 각각은 다른 작업 (위 예제에서 말하자면 A, B, C, …) 을 포함한다. 각 줄에는 다음과 같은 내용이 포함된다. 작업 이름을 나타내는 영문 대문자 하나,

www.acmicpc.net

위상정렬로 접근한 문제다.

 

풀이

입력받은 정보를 기반으로 매 순간 비용의 최댓값으로 갱신하여 위상정렬 순서로 탐색한다. 이후 비용의 최댓값을 출력하면 된다.

각 노드의 진입차수와 노드의 비용 그리고 최종으로 출력할 ans 배열을 생성한다.

가장 먼저 진입차수가 0인 노드를 큐에 넣고 탐색을 시작. 이때 노드에 해당하는 ans는 해당 노드의 cost로 결정된다.

이후 탐색가능한 노드의 ans 값은 ans [현재노드] + cost [탐색가능 노드]와 ans [탐색가능 노드] 중 더 큰 값으로 갱신된다.

다음 탐색을 통해 ans [C]가 8+2의 값으로 갱신되는 모습이다.

다음 탐색으로 ans [E]의 값이 0에서 ans [D] + cost [E]의 값으로 경신.

C노드의 탐색으로 ans [E] 값이 기존보다 더 큰 값인 ans [C] + cost [E]의 값 14로 갱신된다.

이후 E의 진입차수가 0이므로 큐에 삽입되고 탐색이 이루어진다.

ans [F]의 값이 16으로 최종 경신된다.

마지막으로 F노드 방문. 더 이상 탐색가능한 노드가 없으므로 탐색 종료.

ans의 값 중 가장 큰 값을 출력하면 된다.

정답 코드

'Problem Solving > BOJ' 카테고리의 다른 글

[16169] 수행시간  (0) 2023.04.11
[24526] 전화 돌리기  (0) 2023.04.05
[2637] 장난감 조립  (0) 2023.04.01
[13334] 철로  (0) 2023.03.26
[3895] 그리고 하나가 남았다  (0) 2023.03.24

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

 

2637번: 장난감 조립

첫째 줄에는 자연수 N(3 ≤ N ≤ 100)이 주어지는데, 1부터 N-1까지는 기본 부품이나 중간 부품의 번호를 나타내고, N은 완제품의 번호를 나타낸다. 그리고 그 다음 줄에는 자연수 M(3 ≤ M ≤ 100)이 주

www.acmicpc.net

위상정렬 문제다.

 

풀이

처음 문제를 읽었을 때는 기본부품부터 완성품까지 위상정렬로 탐색하여 부품의 개수를 세는 방법으로 접근하였는데, 그렇게 되면 기본부품을 파악하기 힘들어진다.

 

따라서 완성품에서 기본 부품 순서로 위상정렬을 통해 접근하여 탐색하였다. 마지막 노드라면 해당 부품의 cost를 출력하는 방법으로 접근했다. 

 

부품의 비용을 담을 크기 N의 cost배열과, 간선정보를 (다음노드 번호, 비용) 형태로 담을 크기 N의 튜플배열을 생성. 진입차수가 0인 N번 노드를 시작으로 현재 cost X 다음 cost를 배열에 갱신하여 참색을 수행하였다. 입력 예제의 시나리오를 그림으로 표현하면 다음과 같다.

 

각 노드의 진입 차수, 실시간 비용, 그리고 마지막으로 출력할 정답 배열을 생성한다.

가장 첫 번째로 진입 차수가 0인 7번 노드 방문, 4번, 6번, 5번 부품의 비용을 갱신한다.

(현재 비용 * 간선 비용)을 통해 계산이 가능하다.

다음으로 진입 차수가 0인 6번 노드 방문. 탐색을 시작한다. 인접 노드의 비용을 갱신.

3번 노드를 방문. 이때 3번 노드의 경우 더 이상 탐색 가능한 인접 노드가 없다.

3번 부품을 생산하기 위한 다른 부품은 필요 없다는 뜻이므로 ans 배열에 해당 비용을 반영한다.

다음으로 진입 차수가 0인 4번 노드 방문. 마찬가지로 더 이상 탐색 가능한 인접 노드가 없으므로 현재 비용을 ans 배열에 반영한다.

다음으로 5번 노드 방문 인접 노드인 1번 노드와 2번 노드에 (현재 부품 비용 * 간선 비용)을 계산하여 cost배열에 값을 반영한다.

1번 노드 방문. 더 이상 탐색 가능한 노드가 없다. ans 배열에 현재 비용을 반영한다.

마지막으로 2번 노드 방문. 더 이상 탐색 불가능 하므로 ans 배열에 현재 cost를 반영한다.

완성된 ans 배열을 통해 0이 아닌 값들을 출력하면 정답이다.

 

정답 코드

'Problem Solving > BOJ' 카테고리의 다른 글

[24526] 전화 돌리기  (0) 2023.04.05
[14907] 프로젝트 스케줄링  (0) 2023.04.03
[13334] 철로  (0) 2023.03.26
[3895] 그리고 하나가 남았다  (0) 2023.03.24
[3770] 대한민국  (0) 2023.03.14

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

 

13334번: 철로

입력은 표준입력을 사용한다. 첫 번째 줄에 사람 수를 나타내는 양의 정수 n (1 ≤ n ≤ 100,000)이 주어진다. 다음 n개의 각 줄에 정수 쌍 (hi, oi)가 주어진다. 여기서 hi와 oi는 −100,000,000이상, 100,000,0

www.acmicpc.net

스위핑 문제다.

 

풀이

입력되는 구간의 정보를 도착좌표를 기준으로 오름차순으로 정렬한다. 이후 길이가 D 이하인 구간에 대해서만 시작 좌표를 heap에 담아낸 뒤, 매 탐색마다 heap에서 (현재 구간의 도착좌표 - D) 보다 큰 좌표들의 개수를 세면 된다. 해당 값 중 가장 큰 값이 정답이다.

 

예제를 기준으로 다음과 같이 동작한다.

입력되는 구간을 좌표를 기준으로 오름차순, 도착좌표가 같다면, 출발좌표를 기준으로 오름차순으로 정렬한다.

이후 출발좌표를 담아낼 최소 heap 개수의 최댓값을 정답으로 출력하면 된다.

가장 먼저 탐색할 구간의 도착좌표는 20이며 해당 구간의 길이는 D(30) 보다 작으므로 heap에 해당 구간의 출발좌표인 10을 추가한다.

(도착좌표 - D)의 값이 heap의 peek보다 작으므로 다음 탐색으로 넘어간다.

다음으로 탐색할 구간의 출발좌표는 10이며 해당 구간 또한 크기가 D보다 작고

heap의 peek가 (도착좌표 - D) 보다 크므로 heap에 10을 추가하고 다음 탐색으로 넘어간다.

출발 좌표 25를 담아내고, (도착좌표 - D)의 값이 peek보다 작으므로 다음 탐색으로 넘어간다.

동일하게 출발 좌표 25를 heap에 담아내고 (도착지점 - D)가 5로 현재 peek값 10보다 작으므로 다음 탐색으로 넘어간다.

해당 구간은 길이가 D보다 크므로 아무 작업을 하지 않고 다음 탐색을 이어간다.

해당 구간의 출발 좌표 30을 담아낸다. 여기서 heap의 변화가 일어난다.

(도착지점 - D)의 값이 20이므로 peek 값인 10보다 크다. 따라서 heap에서 20보다 작은 값은 삭제한다.

heap의 크기는 3으로 변경되며 peek값은 25로 갱신되었다.

출발좌표 50을 heap에 담고, (도착지점 - D)의 값인 30보다 작은 값들은 heap에서 삭제.

현재 heap의 크기는 2, peek값은 30이 되었다.

마지막 구간의 출발좌표 80을 담고 (도착지점 - D)의 값인 70보다 작은 값은 모두 heap에서 제거.

heap의 크기는 1이며 peek값은 80으로 변경된다.

탐색동안의 heap의 최댓값인 4를 출력하면 정답이다.

 

정답 코드

'Problem Solving > BOJ' 카테고리의 다른 글

[14907] 프로젝트 스케줄링  (0) 2023.04.03
[2637] 장난감 조립  (0) 2023.04.01
[3895] 그리고 하나가 남았다  (0) 2023.03.24
[3770] 대한민국  (0) 2023.03.14
[3653] 영화 수집  (0) 2023.03.12

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

 

3895번: 그리고 하나가 남았다

입력은 여러개의 데이터 행이며, 각 데이터는 다음과 같은 3개의 숫자로 이루어진다. n k m 마지막 데이터 행 다음은 3개의 0으로 이루어진 행이다. 각 수는 다음 범위를 만족한다. 2 ≤ n ≤ 10000, 1

www.acmicpc.net

세그먼트 트리 문제다. 금방 풀 수 있을줄 알고 접근했는데, 생각보다 오랜시간이 소요됐다.

 

풀이

1부터 n까지의 숫자가 몇개가 있는지를 나타내는 세그먼트 트리를 구현. 남아있는 숫자중 x번째 수를 반환하는 함수와 구간별 숫자의 갯수를 반환하는 함수를 구현하여 접근하였다.

 

k번째 돌이라는 의미는 이전에 치워진 돌부터 시작하여 k%(현재 남아있는 돌의 갯수)번째 돌을 의미한다. 즉 치워진 돌 앞에 몇개의 돌이 있는지 정보를 가지고 있어야 한다는 점이다. 따라서 치워진 돌 앞의 돌의 갯수를 cnt라고 정의할 때, 우리는 (k+cnt)%현재 남아있는 돌의갯수 번째의 돌을 치우면 된다.

 

예제 "8 5 3"을 기준으로 다음과 같은 시나리오를 그릴 수 있다.

초기 상태의 구간 합 세그먼트 트리 생성

가장 먼저 m번째 돌인 3번 돌을 제거. 앞에는 두개의 돌이 있다. 

k + cnt % 남아있는 돌의 갯수. 즉 5 + 2 % 7 계산을 통해 0번째 돌을 제거해야하는데, 모듈러 계산에 의한 순서이므로 마지막 돌, 즉 일곱번 째 돌인 8번 돌을 제거하면 된다. 이때 앞에 남아있는 돌의 갯수는 6개가 된다.

6 + 5 % 6 계산. 5이므로 다섯번째 돌인 6번 돌을 제거한다. 

앞순번에 다섯번째 돌을 제거했기에 4 + 5 % 5 계산, 4번째 돌인 5번 돌 제거

다음으로는 3 + 5 % 4 계산, 4번째 돌인 7번 돌 제거

3 + 5 % 3 계산, 남아있는 돌 중 2번째 돌 2번 돌을 제거한다.

1 + 5 % 2 계산, 0번째 돌 즉 남아있는 마지막 돌인 4번 돌 제거.

마지막으로 1 + 5 % 1 계산, 0번째 즉 남아있는 마지막 돌 1번 돌이 제거된다.

마지막으로 제거된 1을 출력하면 정답이다.

 

정답 코드

'Problem Solving > BOJ' 카테고리의 다른 글

[2637] 장난감 조립  (0) 2023.04.01
[13334] 철로  (0) 2023.03.26
[3770] 대한민국  (0) 2023.03.14
[3653] 영화 수집  (0) 2023.03.12
[7578] 공장  (0) 2023.03.11

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

 

세그먼트 트리문제다. [7578] 공장 문제와 같은 풀이로 접근가능하다.

 

풀이

[7578] 공장 문제와 달리 유의할 점은 입력되는 간선의 정렬이 필요하다는 점이다.

 

출발지 기준 오름차순, 출발지가 같다면 도착지기준 오름차순으로 고속도로 정보를 정렬한 뒤, 매 순간 도착도시 다음번호 ~ 마지막 도착도시 구간의 건설된 고속도로의 개수 총합을 출력하면 된다.

 

입력 예제를 기준으로 시나리오를 그려보면 다음과 같다.

 

좌측의 N개의 도시, 우측의 M개의 도시와 정렬된 간선 그리고 구간 합 세그먼트 트리를 생성한다.

 

1번 도시와 4번 도시를 연결, 4번은 가장 마지막 도시이므로 구간합 조회 시 범위를 넘어가게 되어 0을 반환하게 된다.

다음 탐색을 위해 4번 노드에 1 추가.

 

2번 도시와 3번 도시 연결, 이때 3번 도시 이후의 구간 즉 4~4번 구간의 고속도로의 개수 1을 정답에 추가한다.

이후 3번 노드에 1 추가.

 

3번 도시와 1번 도시 연결, 2번 도시부터 4번 도시 구간의 고속도로의 수를 조회한다. 고속도로의 개수 2가 반환된다.

이후 1번 노드에 1 추가.

 

마지막으로 3번 도시와 2번 도시 연결, 3번 도시와 4번 도시 구간합을 조회. 정답에 해당 구간값 2를 추가한다.

2번 노드에 1 추가.

 

정답 코드

'Problem Solving > BOJ' 카테고리의 다른 글

[13334] 철로  (0) 2023.03.26
[3895] 그리고 하나가 남았다  (0) 2023.03.24
[3653] 영화 수집  (0) 2023.03.12
[7578] 공장  (0) 2023.03.11
[1280] 나무 심기  (1) 2023.03.09

+ Recent posts